3

I don't know what makes a difference here.

a = 24
b = 60
comp1 = a > 42 or b == 60
comp1 # => false
comp2 = (a > 42 or b == 60)
comp2 # => true

Could someone explain what's going on and why the return values are different?

sawa
  • 165,429
  • 45
  • 277
  • 381
Edzzn
  • 45
  • 7
  • 1
    You may be [confusing `or` with `||` here.](http://stackoverflow.com/questions/2083112/difference-between-or-and-in-ruby) – Michael Berkowski Jun 25 '15 at 17:32
  • `or` and `and` are meant to be used as control flow operators. Whereas `||` and `&&` are meant to be logical operators. – engineersmnky Jun 25 '15 at 17:35
  • @engineersmnky Given that every expression in Ruby has an evaluated value, that does not make any difference. – sawa Jun 25 '15 at 17:36
  • 2
    @sawa: semantics, man. Conveying message and all that. Then again, lowered precedence helps with using for control flow. – Sergio Tulentsev Jun 25 '15 at 17:37
  • Helps to remember that `and, or` are sometimes referred to as logical _composition_ operators. – Michael Berkowski Jun 25 '15 at 17:41
  • @SergioTulentsev Control flow operators do mean something (and more than semantically) even if @sawa doesn't think so. Take this for example `a = 12 and a += 1 #=> 13` vs `b =12 && b += 1 #=> NoMethodError: undefined method '+' for nil:NilClass` this is because the first version says assign `a` and if `a` is not falsey then evaluate `a += 1` the second version the assingment will occur after the logical expression is evaluated and since `12` is truthy it then moves on to `b += 1` but `b` is still `nil` so it raises an error. – engineersmnky Jun 25 '15 at 18:00
  • @engineersmnky: yeah, I know :) – Sergio Tulentsev Jun 25 '15 at 18:33

3 Answers3

4

This is due to the strength of the operator binding, as operators are applied in a very particular order.

or is very loose, it has the lowest priority. The || operator is very strong, the opposite of that. Note how in that table || comes before =, but or comes after? That has implications.

From your example:

comp1 = a > 42 or b == 60

This is how Ruby interprets this:

(comp1 = (a > 42)) or (b == 60)

As such, the entire statement returns true but comp1 is assigned false because it doesn't capture the whole thing.

So to fix that, just use the strong binding version:

comp1 = a > 42 || b == 60
# => true
tadman
  • 208,517
  • 23
  • 234
  • 262
3

It has all to do with operator precedence. or has lower priority than =, so

comp1 = a > 42 or b == 60

is executed as

(comp1 = a > 42) or (b == 60)

You need to enforce precedence by parentheses. Or be a good ruby coder and never* use and/or (use &&/|| instead)

* never, unless you know what you're doing. A rule of thumb is: &&/|| for logical operations, and/or - for control flow.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • Thank you for adding the `*` to *never* and for explaining that `and` and `or` are for control flow not logical operations. – engineersmnky Jun 25 '15 at 17:36
1

In Ruby, assignment (=), has higher precedence than the written or operator, so the first line is interpreted as this:

(comp1 = a > 42) or (b == 60)

That means that comp1 is being assigned the value of a > 42, which is obviously false. The parenthesis in the second expression resolve the issue.

In general, in Ruby, you use || instead of or, and likewise, && in place of and.

Linuxios
  • 34,849
  • 13
  • 91
  • 116