2

statement 1:

[2,4,6,7,8].each do |i|
    (i % 2 == 0) || (puts "Not even" && break)
    puts i
end

statement 2:

[2,4,6,7,8].each do |i|
    (i % 2 == 0) || (puts("not even") && break)
    puts i
end

Statement 1 breaks but doesn't put, and statement 2 puts but doesn't break

Why does it behave this way, and how could I write this expression better? (I don't mean finding odd #s, I mean || && statements)

Peter R
  • 3,185
  • 23
  • 43
  • In either case, you are writing non-idiomatic Ruby code. Code should be easily read and understood. Any time it can't be quickly grasped it needs to be refactored to be simpler. Complex, convoluted, or obfuscated code is a maintenance nightmare and very often a bug in waiting. – the Tin Man Oct 09 '15 at 15:54

4 Answers4

4

Statement 1:

Ruby interprets it like this: puts("Not even" && break). So break is executed before puts argument is parsed.


Statement 2:

puts("not even") returns nil and so break is not executed at all


If you realy want it to be inline I'd suggest writing this without &&: (puts "Not even"; break)

nsave
  • 984
  • 9
  • 27
4

how could I write this expression better

Don't [write expressions where you mean to use flow-control statements].

Using boolean expressions for flow-control like that is fragile at best. And, more likely, is just confusing and hard to understand. Compare to this, for example.

[2,4,6,7,8].each do |i|
  if i % 2 != 0 # if i.odd?
    puts 'not even'
    break
  end

  puts i
end

Which style to choose, depends on what you're after: readability or terseness. If you're not participating in code golf, I'd say, choose readability every time.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
3

puts "Not even" && break is equal to puts("Not even" && break), break will be executed, so the loop will break.

puts("not even") will return nil.

puts("not even") && break is equal to: nil && break, break isn't executed, so the loop doesn't break.

pangpang
  • 8,581
  • 11
  • 60
  • 96
2

The reason is that function application has a lower precedence than any operators in Ruby.

So

puts "Not even" && break

becomes

puts ("Not even" && break)

(the && is evaluated before the function call). See also Ruby operator precedence

Community
  • 1
  • 1
Frank Schmitt
  • 30,195
  • 12
  • 73
  • 107
  • To avoid this, use `and` instead of `&&`, which has a much lower operator precedence. – mhutter Oct 09 '15 at 09:45
  • 1
    @mhutter In my experience, relying on operator precedence is always a bad idea (apart from the most obvious cases). Better use parentheses when there's the slightest doubt - even if you exactly know what a given expression does, the next programmer (which might very well be yourself in a couple of months/years) might not know the rules as good as you. – Frank Schmitt Oct 09 '15 at 11:06
  • 1
    Yes I absolutely agree but I felt it had to be mentioned for completeness :-) – mhutter Oct 09 '15 at 12:26