Blocks and Precedence

Mon Apr 14 09:48:00 UTC 2008

There are two different forms for passing a block to a method in Ruby, one with braces, and one with do/end. I used to think they were equivalent, but recently learned that there is a subtle difference having to do with precedence. As an example

def block_test(arg1)
    "I received '#{arg1}' and " << (block_given? ? "a block which yielded '#{yield}'" : "no block")
end

def speak
    "I've been told to say " << (block_given? ? yield : "nothing")
end

Looking at the brace form of passing blocks to methods, you can see that whether you surround your arguments with parentheses changes who gets the block

block_test speak { "hello" } 
# => "I received 'I've been told to say hello' and no block"

block_test(speak) { "hello" } 
# => "I received 'I've been told to say nothing' and a block which yielded 'hello'"

This is fairly intuitive. However, if you use the do/end form for the block, it gets passed as an argument to block_test whether you use parentheses or not

block_test speak do
    "hello"
end
# => "I received 'I've been told to say nothing' and a block which yielded 'hello'"

block_test(speak) do
    "hello"
end
# => "I received 'I've been told to say nothing' and a block which yielded 'hello'"

Tags: blocks ruby

Comments

Have your say

A name is required. You may use HTML in your comments.