I recently discovered a Ruby gotcha which I don't completely understand. So, can someone explain to me why these 2 following statements in Ruby are not the same-
puts "foo" and return if true
VS
if true
puts "foo"
return
end
To understand oneliners like the one in your question, you need to memorize Ruby operators and their precedence. Or, more precisely, Ruby syntax. You need to see the statements in exactly the same way that Ruby interpreter does. It must become your second nature. Let us now take a look at your one-liner
puts "foo" and return if true
Let us separate the unrelated issues first. Keyword return
is only applicable inside methods or lambdas and is not really the subject of your question. Furthermore, trailing if true
is always valid and thus seems unnecessary. To discuss your question in general, let us define method #bar
and a variable baz
def bar
puts "bar"
end
baz = true
and let us talk about a modified one-liner
puts "foo" and bar if baz
If you have memorized Ruby syntax, you will be able parenthesize the line exactly as Ruby sees it:
( puts( "foo" ) and ( bar ) ) if ( baz )
Trailing if
behaves like an operator with very low priority. Whole line from the beginning up to if
is executed only if baz
is truey, which it is. Therefore,
puts "foo" and bar
gets executed. It is parenthesized as follows:
puts( "foo" ) and ( bar )
You can see that puts "foo"
is executed first, printing foo
on the screen and returning nil
. Since nil
is falsey, operator and
just returns it and bar
on its right side never gets executed.
As for
if baz
puts "foo"
bar
end
it is equivalent to:
( puts( "foo" ); bar ) if ( baz )
You can see the difference: puts "foo"
and bar
are not joined by and
, but are independent logical lines. The return value of the first line is discarded and does not affect execution of the second line.
Finally, let us look at what happens upon replacing and
with &&
. Because &&
operator has much higher priority than and
, oneliner
puts "foo" && bar
becomes
puts( "foo" && bar )
In other words, value of "foo" && bar
would be computed first, and then passed as an argument to #puts
method. Because string "foo"
is considered truey, execution proceeds to bar
, which prints "bar"
on the screen and returns nil
. You can try by yourself that the value of
"foo" && bar
is nil
, with "bar"
printed on the screen as a side effect.
puts( "foo" && bar )
thus becomes
puts( nil )
which causes an empty line to be printed on the screen.
The morale is that that one should learn the syntax. Ruby designer made a big step of making the code readable at a glance like a book.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With