In ruby, what does "&block" do? [duplicate] - ruby

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What’s this &block in Ruby? And how does it get passes in a method here?
I dont Understand the &block part, what does it do?
here is an example:
def method_missing(method_name, *args, &block)
#messages << method_name
#object.send method_name, *args, &block
end

Blocks give you an opportunity to state a callback to pass on to a method.
The & is key here - like #pst mentioned, it "promotes" the block to a Proc and binds the Proc to the variable with the given name.
With &
def time(&block)
puts block
end
time
# => nil
time { foo }
# => #<Proc:0x00029bbc>
Without &
def time(block)
puts block
end
time { foo }
# => ArgumentError: wrong number of arguments (0 for 1)
# Because & isn't included, the method instead expected an arguement,
# but as a block isn't a arguement an error is returned.

Answering "And how would I pass it to another method?" comment by Brian:
Like this:
def compose init_value, n=2, &b
if n==0 then init_value else
b.call( compose init_value, n - 1, &b )
end
end
compose 2 do |n| n * n end
#=> 16
compose 2, 4 do |n| n * n end
#=> 65536
compose 2, 4 do |n| n * 0.5 end
#=> 0.125
This is a recursive method that recursively applies the same block to a number several times. Here, the block packaged into b argument gets called, but at the same time it is passed on recursively to compose method, while n argument is decremented by 1. In the same way, b could be passed to any method, like map, reduce, anything.
Whereas, should you not need to pass the block to another method, you could simply use yield:
def apply_block_to_1_2_3
return yield( 1 ), yield( 2 ), yield( 3 )
end
apply_block_to_1_2_3 { |n| n * n }
#=> [1, 4, 9]
May the force be with you.

It converts the block to a proc object that can be passed on to another method.

when you call a method with a block, there are 2 ways to use that block:
call yield inside method
convert it into a Proc object by prepending & to it
with second way you can pass it to another method.
so in your case it transforms the given block into a Proc and calling method_name with it.
think of it as you can pass a block just like any argument.

Related

Ruby Yield and For Loop

I'm working my way through a simple tutorial of each vs for loops in Ruby. This is supposed to be one of the simpler examples but for some reason, I don't understand the interaction between the yield statements and the for loop.
class MyEachThing
def each
yield 1
yield 42
yield 2
yield 42
yield 3
end
end
for i in MyEachThing.new
p i
end
# >> 1
# >> 42
# >> 2
# >> 42
# >> 3
Yield in this next example that I made up makes sense to me:
def calling
p yield(45)
end
calling {|i| i*2}
I just don't get how the first example works. Thank you for the help.
for i in MyEachThing.new
p i
end
is similar to this:
MyEachThing.new.each do |i|
p i
end
which means, you are calling each method on MyEachThing instance and passing i to the block.
And, yield is equivalent to: block.call means, you're calling the block with the passed argument (in this case i).
yield i is equivalent to: block.call(i) and your block is just printing the value of i.

Ruby: Difference between passing `&proc` and `proc` to a method

I have a bit of code modified slightly from a question on codeacademy. The code is :
def print_list(array, first = 1)
counter = first
array.each do |array|
puts "#{yield counter} #{array}"
counter = counter.next
end
end
proc = Proc.new do |n|
"[#{100*n}]:"
end
print_list ["alpha", "beta", "gamma"], 5, &proc
If I remove the & from the last line Ruby throws me an argument error. What is the purpose of the & here?
If you remove the &, then print_list treats proc as a third argument to itself, instead of a block. The & symbol transforms the Proc object into a block, which is called inside print_list by the yield keyword.
More succinctly,
proc is just an argument, &proc is a reference to the block passed to the method.
You might find this article useful to understand the differences between proc and blocks
The & indicates that the proc should be passed as a block.
Without it, the "proc" will just be another (third) parameter so you'll get the argument error (3 for 2)
It's possible to pass it without the & and use it in your print_list method directly as a proc... but first can't be optional then. You'll need to pass first or at the very least nil.
def print_list(array, first, proc)
counter = first || 1
array.each do |array|
puts "#{proc.call counter} #{array}"
counter = counter.next
end
end

What do c == self and yield do?

Can you help me understand what this class does and how we can make use of it?
class Integer
def myt
c=0
until c == self
yield(c)
c+=1
end
self
end
end
Thank you.
x = Integer.new
x.myt
I tried to test it but it doesn't work. Error is: "no block given (yield)"
Also, in my book it says to test like this:
5.myt (|| puts "I'm on iteration #{i}! "} but it also gives an error - not sure why or what this line of code means.
allonhadaya and PNY did a good job explaining the purpose (enumeration) of the myt method.
Regarding your two questions mentioned in the title:
1.) What does 'c == self' do?
The '==' operator checks whether the integer c and Integer object you instantiate, are equal in value. If they are, the expression evaluates to true.
2.) What does 'yield' do?
The 'yield' statement passes control from the current method to a block which has been provided to the method. Blocks are ruby's implementation of a closure which, simple put, means that a method can be "extended" by calling the method with a block of additional code as long as the method supports a block (ie. incorporates yield statements)
The method seems to be a times implementation.
Basically 5.times { |i| puts i } and 5.myt { |i| puts i } will do exactly the same thing.
First, it sets a counter to 0, c = 0. Then you have a conditional where it checks if c is equal with self which will always be the integer attached to the method myt. It, then yields the counter and return self when is done.
Looks like it enumerates the values between zero inclusively and self exclusively.
allon#ahadaya:~$ irb
irb(main):001:0> class Integer
irb(main):002:1> def myt
irb(main):003:2> c=0
irb(main):004:2> until c == self
irb(main):005:3> yield(c)
irb(main):006:3> c+=1
irb(main):007:3> end
irb(main):008:2> self
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> 5.myt { |i| puts i }
0
1
2
3
4
=> 5
irb(main):012:0>
Using the example your book gave --
5.myt {|i| puts "I'm on iteration #{i}! "}
#You were missing an object in the pipes and a curly bracket before the pipes (not parentheses)
Allows you to see the internal workings of your myt method. Initializing variable c with a value of 0 the method executes an until look until the condition "c == self" is satisfied. Self references the object, here 5, which the method is acting on.
Therefore ...
def myt
until c == 5 #Until this is true
yield(c) #Do this .. here yield will do whatever the block specified
c+=1 #Increment on each iteration the value of variable c by 1
end #closing the until loop
self #return self
end
The yield within the method passes control from your method to the parameter, a block, back to the method.
Yield therefore allows you to build methods which can have similar patterns but with block you customize it to do your particular need.
If instead of putting each number maybe all you want to do is put the odd integers between 0 and the integer you call the method on --
5.myt {|i| puts i if i.odd?} # returns I am odd: 1 and I am odd: 3
I would suggest that you write your own blocks here to see how yield works and how you can keep the same method but pass in different blocks and create different method outputs!

Use of yield and return in Ruby

Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.

Passing a method as a parameter in Ruby

I am trying to mess around a little bit with Ruby. Therefor I try to implement the algorithms (given in Python) from the book "Programming Collective Intelligence" Ruby.
In chapter 8 the author passes a method a as parameter. This seems to work in Python but not in Ruby.
I have here the method
def gaussian(dist, sigma=10.0)
foo
end
and want to call this with another method
def weightedknn(data, vec1, k = 5, weightf = gaussian)
foo
weight = weightf(dist)
foo
end
All I got is an error
ArgumentError: wrong number of arguments (0 for 1)
The comments referring to blocks and Procs are correct in that they are more usual in Ruby. But you can pass a method if you want. You call method to get the method and .call to call it:
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
...
weight = weightf.call( dist )
...
end
You want a proc object:
gaussian = Proc.new do |dist, *args|
sigma = args.first || 10.0
...
end
def weightedknn(data, vec1, k = 5, weightf = gaussian)
...
weight = weightf.call(dist)
...
end
Just note that you can't set a default argument in a block declaration like that. So you need to use a splat and setup the default in the proc code itself.
Or, depending on your scope of all this, it may be easier to pass in a method name instead.
def weightedknn(data, vec1, k = 5, weightf = :gaussian)
...
weight = self.send(weightf)
...
end
In this case you are just calling a method that is defined on an object rather than passing in a complete chunk of code. Depending on how you structure this you may need replace self.send with object_that_has_the_these_math_methods.send
Last but not least, you can hang a block off the method.
def weightedknn(data, vec1, k = 5)
...
weight =
if block_given?
yield(dist)
else
gaussian.call(dist)
end
end
...
end
weightedknn(foo, bar) do |dist|
# square the dist
dist * dist
end
But it sounds like you would like more reusable chunks of code here.
You can pass a method as parameter with method(:function) way. Below is a very simple example:
def double(a)
return a * 2
end
=> nil
def method_with_function_as_param( callback, number)
callback.call(number)
end
=> nil
method_with_function_as_param( method(:double) , 10 )
=> 20
The normal Ruby way to do this is to use a block.
So it would be something like:
def weightedknn(data, vec1, k = 5)
foo
weight = yield(dist)
foo
end
And used like:
weightedknn(data, vec1) { |dist| gaussian( dist ) }
This pattern is used extensively in Ruby.
You can use the & operator on the Method instance of your method to convert the method to a block.
Example:
def foo(arg)
p arg
end
def bar(&block)
p 'bar'
block.call('foo')
end
bar(&method(:foo))
More details at http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
You have to call the method "call" of the function object:
weight = weightf.call( dist )
EDIT: as explained in the comments, this approach is wrong. It would work if you're using Procs instead of normal functions.
I would recommend to use ampersand to have an access to named blocks within a function. Following the recommendations given in this article you can write something like this (this is a real scrap from my working program):
# Returns a valid hash for html form select element, combined of all entities
# for the given +model+, where only id and name attributes are taken as
# values and keys correspondingly. Provide block returning boolean if you
# need to select only specific entities.
#
# * *Args* :
# - +model+ -> ORM interface for specific entities'
# - +&cond+ -> block {|x| boolean}, filtering entities upon iterations
# * *Returns* :
# - hash of {entity.id => entity.name}
#
def make_select_list( model, &cond )
cond ||= proc { true } # cond defaults to proc { true }
# Entities filtered by cond, followed by filtration by (id, name)
model.all.map do |x|
cond.( x ) ? { x.id => x.name } : {}
end.reduce Hash.new do |memo, e| memo.merge( e ) end
end
Afterwerds, you can call this function like this:
#contests = make_select_list Contest do |contest|
logged_admin? or contest.organizer == #current_user
end
If you don't need to filter your selection, you simply omit the block:
#categories = make_select_list( Category ) # selects all categories
So much for the power of Ruby blocks.
Similarly to a Proc or a method call, you can also pass a lambda as weightf parameter :
def main
gaussian = -> (params) {
...
}
weightedknn(data, vec1, k = 5, gaussian, params)
# Use symbol :gaussian if method exists instead
end
def weightedknn(data, vec1, k = 5, weightf, params)
...
weight = weightf.call(params)
...
end
you also can use "eval", and pass the method as a string argument, and then simply eval it in the other method.

Resources