Reputation: 1488
I can pass arguments to functions like this:
func 1, 2, 3
or I can use brackets like:
func(1, 2, 3)
Later on I learned about functions like list.each
which I pass (not sure if this is what's really happening) a block to operate on each element:
list.each {|x| puts x}
I assumed this just passed the block as an argument to the each
function, but this doesn't seem to be the case because:
list.each( {|x| puts x} )
does not work.
I realized this when shown:
5.upto(9) {|x| puts x}
Which doesn't make sense at all if the block is simply an argument.
What's going on here? Any resource you can point me to to help explain this, and perhaps other structure things that aren't immediately obvious?
Upvotes: 4
Views: 231
Reputation: 187004
methods can accept exactly one block, sort of as a special argument.
def foo
yield 123
end
foo { |x| puts x }
#=> 123
Note how that method accepts zero arguments, but still accepts a block. That's because this syntax of hanging a block off a method is sort of a special case. Any block passed to a method can be run with the yield
keyword. And you can even ask if a block was passed in with the block_given?
keyword.
If you want to capture it in a local variable, you can do that with some special syntax.
def foo(a, &block)
block.call a
end
foo(123) { |x| puts x }
#=> 123
In this case, you are capturing the block argument explicitly, with that &
prefix in the argument list. You now have a variable for that block, which you can send the call
message in order to execute. Just know this must appear at the end of the argument list.
Also note the parens. foo(123) { |x| puts x }
. The argument list stops, the parens close and the attached block comes after. Again, because this is a special case in the syntax.
Upvotes: 4
Reputation: 55718
Blocks are indeed a bit special, but can also be used as arguments. Consider this function:
def greet
yield "Hello"
end
greet{ |greeting| puts "#{greeting} to you" }
You could also write the exact same thing like this:
def greet(&block)
block.call("Hello")
end
greet{ |greeting| puts "#{greeting} to you" }
# which is equivalent to:
my_proc = proc{ |greeting| puts "#{greeting}, nice to see you." }
greet(&my_proc)
In the end, blocks are a special form of procs with a special syntax which makes them more usable. But you can still access the procs and pass them around.
Upvotes: 6