Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby's one liner "and return"

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
like image 282
Yoni Avatar asked Sep 11 '25 14:09

Yoni


1 Answers

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.

like image 175
Boris Stitnicky Avatar answered Sep 13 '25 05:09

Boris Stitnicky