sawa's answer is correct, but as the OP has asked for more clarification, I'm supplying my own answer.
All four of these method calls behave the same, passing a block to a foo
method:
foo { ... }
foo do ... end
foo() { ... }
foo() do ... end
When you write two methods and a block, without parentheses around the arguments, it is unclear which method the block goes with:
foo bar { ... }
foo bar do ... end
The question is: "Am I passing a block to bar
, and then passing its return value to foo
? Or am I calling foo
with bar
as an argument and also passing along a block?"
With parentheses, you can make this clear using either block style:
# Passing a block to `bar`, and then passing the result to `foo`
foo( bar { ... } )
foo( bar do ... end )
# Passing an argument and block to `foo`
foo( bar ) { ... }
foo( bar ) do ... end
The difference between {…}
and do…end
that you have run into is where Ruby chooses to put the parentheses when you omit them. The two block notations have different precedence, and so you end with different results:
# Passing a block to `bar`, and then passing the result to `foo`
foo bar{ ... }
foo( bar do ... end )
# Passing an argument and block to `foo`
foo bar do ... end
foo( bar ){ ... }
So, specifically in your case:
# This code…
p a.sort do |x,y|
y <=> x
end
# …is the same as this code:
b = a.sort
p(b){ |x,y| y <=> x }
# Note that you are passing a block to the `p` method
# but it doesn't do anything with it. Thus, it is
# functionally equivalent to just:
p a.sort
And,
# This code…
p a.sort { |x,y|
y <=> x
}
# …is functionally the same as this code:
b = a.sort{ |x,y| y <=> x }
p b
Finally, if you still don't get it, perhaps deeply considering the following code and output will help:
def foo(a=nil)
yield :foo if block_given?
end
def bar
yield :bar if block_given?
:bar_result
end
foo bar { |m| puts "block sent to #{m}" }
#=> block sent to bar
#=> foo got :bar_result
foo( bar do |m| puts "block sent to #{m}" end )
#=> block sent to bar
#=> foo got :bar_result
foo( bar ){ |m| puts "block sent to #{m}" }
#=> foo got :bar_result
#=> block sent to foo
foo bar do |m| puts "block sent to #{m}" end
#=> foo got :bar_result
#=> block sent to foo
Notice that the first and last examples in the code immediately above differ only in whether they use {…}
or do…end
for the block.