Ruby do/end vs braces
Solution 1
That's because the second line is interpreted as:
p(a.map) do ... end
instead of:
p(a.map do ... end)
The grammar is ambiguous in this case and do
doesn't seem to bind as strongly as {
.
Solution 2
That has to do with the difference in associativity of the {
character and the do
keyword.
In the first case, the block is interpreted as a block argument to the map
function. The result of the map function is the argument to the p
function.
In the second case, the block is interpreted as a block argument to the p
function, while the a.map
is interpreted as the first argument to the p
function. Since a.map
evaluates to a
, this prints the original array. The block is effectively ignored in this case.
Solution 3
With the do/end
syntax you are passing the block to p
as a second argument, rather than to the map. You get the same result with:
p a.map
The block is ignored by p
as it does not produce anything on inspect
.
Related videos on Youtube
Comments
-
Grandpa almost 4 years
Why does this map expression produce different results depending on whether I use braces or do/end?
a = [1,2,3,4,5] p a.map { |n| n*2 } #=> [2,4,6,8,10] p a.map do |n| n*2 end #=> [1,2,3,4,5]
-
fotanus almost 11 yearsThis holdstrue up to today
-
Cees Timmerman over 3 yearsDoes this answer your question? Using do block vs braces {}
-
-
sawa about 13 years@Grandpa It's not particularly about 'p'. It's about the strength/priority between method's taking argument/blocks and {}, do end
-
karatedog almost 12 yearsAnd how is it possible to use
do...end
properly with a multiline block so thatmap
gets it as parameter? Braces - as your suggestion - won't do it, Ruby throws an error,unexpected keyword_do_block
even the whole block is one line. -
DarkDust almost 12 years@karatedog: You'll probably need to use an intermediate variable here as the parser doesn't support what you want.
-
karatedog almost 12 years@DarkDust Thanks, but I cannot use an intermediate variable when the Enumerator is infinite because I should have to know beforehand how much items I should generate into that intermediate variable.
-
DarkDust almost 12 yearsI don't get what you mean, of course you can do
foo = a.map do ... end ; p(foo)
. It is the exact same semantics, becausemap
always needs to aggregate an array to pass on first. Whether that array is then stored in a variable or passed as parameter to another method makes no difference, the array needs to be created first no matter what.