Question

Can anyone explain why this is happening?

[1].reject{|n| [].include? n or n == 1} # => [] 
[1].reject{|n| [].include? n || n == 1} # => [1] 

I am not sure what it means for || to have higher precedence, or why it would affect this outcome.

Was it helpful?

Solution

The answer is due to their precedence relative to the #include? method call without parentheses.

or binds less tightly (has lower precedence, i.e. evaluates later) than the method call .include? n, and so the expression evaluates as ([].include? n) or (n == 1) #=> true

||, on the other hand, binds more tightly (has higher precedence, i.e. evaluates earlier) than the method call, and so the expression evaluates as [].include?((n || (n == 1))) #=> false.

Precedence refers to the order of operations. It's like in algebra class when you learned PEMDAS:

  • parentheses,
  • exponentiation,
  • multiplication/division,
  • addition/subtraction.

Programming languages, like mathematical notation, have to obey a specific order of operations in order to evaluate non-ambiguously. In Ruby, for the operations you have here, it goes:

  • ||,
  • method call,
  • or.

OTHER TIPS

It is indeed due to precedence and parenthesis will (hopefully) help clarify things.

These two lines are equivalent:

[1] pry(main)> [1].reject{|n| [].include? n or n == 1}
=> []
[2] pry(main)> [1].reject{|n| ([].include? n) or (n == 1)}
=> []

As are these:

[3] pry(main)> [1].reject{|n| [].include? n || n == 1}
=> [1]
[4] pry(main)> [1].reject{|n| [].include? (n || n == 1)}
=> [1]

Notice that in [4] the argument to [].include? is the result of evaluating the statement n || n == 1, which returns true. Since the empty array [] does not include true the block evaluates to false and the n is not rejected.

In [2], however, the argument passed to [].include? is just n. Since n is equal to 1 the block evaluates to true and n is indeed rejected. Note also that in [1] and [2] n == 1 is never even executed.

So to get the || version to behave like the or version just do this:

[5] pry(main)> [1].reject{|n| ([].include? n) || (n == 1)}
=> []

Hopefully this clears things up.

[1].reject{|n| [].include? n || n == 1}

In above example as || has higher precedence n || n will execute and then .include?. So output is [1].

[1].reject{|n| [].include? n or n == 1}

In above example .include? will execute w.r.t n. So output is [].

If you would like to execute n or n first then use this:

[1].reject{|n| [].include? (n or n) == 1}

which will give output [1].

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top