7

Here are two tests:

if [1,2,3,4].include? 2 && nil.nil?
  puts :hello
end
#=>

and

if [1,2,3,4].include?(2) && nil.nil?
  puts :hello
end
#=> hello

The above tells me that && has higher precedence than method arguments so it logically ands 2 && nil.nil? which is true and passes that as an argument to include?.

However, there is this test:

if [1,2,3,4].include? 2 and nil.nil?
  puts :hello
end
#=> hello

So this is telling me that method arguments and 'and' have the same precedence (or method args are higher than 'and') since it passed 2 to include? before it processed 'and'.

Note: I understand that && and and have different precedence. The question is not regarding this but regarding and or or vs the arguments to a ruby method.

I can't find documentation that affirms this. For instances, this doesn't mention method arguments at all: http://phrogz.net/programmingruby/language.html#table_18.4 or http://romhack.wikia.com/wiki/Ruby_operators.

Could anyone explain this behavior? Namely in that how does ruby know to pass values as arguments to a method vs. process operators?

jshort
  • 1,006
  • 8
  • 23
  • 1
    As part of the parsing, and `and` and `&` have a different precedence. Once you start calling methods with no parentheses it gets pretty convoluted pretty quickly, but it'll stop thinking something is an argument at the first whitespace, iirc. Or the other way around. – Dave Newton Jan 22 '15 at 19:10
  • 4
    My rule of thumb to avoid this confusion: include the parentheses when calling methods with arguments even if they're not necessary and never use `and` or `or`. Ruby people tend to have a pathological fear of parentheses so using them gets me lots of dirty looks but I don't care, my code is readable rather than a confusing attempt at poetry. – mu is too short Jan 22 '15 at 19:14
  • + 1. Insofar as this aspect of Ruby's behavior is modeled on Perl, you may find Perl's operator-precedence chart to be helpful; see http://perldoc.perl.org/perlop.html#Operator-Precedence-and-Associativity. That chart *does* include function calls -- which have different "leftward" and "rightward" precedence. (For example, `1 && foo 2 && 3` means `1 && (foo (2 && 3))` -- the function-call has higher precedence than the first `&&`, but lower precedence than the second `&&`.) Of course, for Ruby that chart is not even remotely authoritative. – ruakh Jan 22 '15 at 19:17
  • My money is on all operators having precedence over method calls. – Cary Swoveland Jan 22 '15 at 19:42
  • @CarySwoveland, but my final test proves otherwise. It says that either A) method call arguments have the same precedence as the 'and' operator, or that B) method call arguments have higher precedence than the 'and' operator. – jshort Jan 22 '15 at 19:52
  • It's fortunate I placed only a small bet. btw, couldn't you have just written `true` rather than `nil.nil?`? Great question, btw. – Cary Swoveland Jan 22 '15 at 20:08
  • @μ, yeah, yeah, yeah, but why?, why? why? (is OP getting those results). – Cary Swoveland Jan 22 '15 at 20:14
  • 2
    @muistooshort, perhaps I should say, "'and' and 'or' one condemns, with that I concur, needless parens?, only maybe, there I'll demure, but let's not forget what still must be penned: it's insight I say, of that I am sure!" – Cary Swoveland Jan 22 '15 at 21:23
  • From the table you have given you can see `#defined?` given in the precedence table. This is just a normal Ruby method defined in `Object` so you can just take this as the priority of method calls. – hahcho Jan 24 '15 at 10:19

2 Answers2

1

As you said && and and have different precedence, however the explanation for the following example:

if [1,2,3,4].include? 2 and nil.nil?
  puts :hello
end
#=> hello

is the binding strenght of the and as you can read here: Difference between "and" and && in Ruby?

This basically explains that 2 and nil.nil? will be evaluated as nil, however it will return 2 as can be seen in this example:

foo = :foo
bar = nil

a = foo and bar
# => nil
a
# => :foo

a = foo && bar
# => nil
a
# => nil
Community
  • 1
  • 1
0

I've never seen any documentation about method argument precedence, but one rule of thumb I use when seeing method arguments is to mentally strip the whitespace wherever possible in the arguments and still have the same expression. This normally gives me the precedence:

[1,2,3,4].include? 2&&nil.nil? is the same expression, but you cannot strip the whitespace in [1,2,3,4].include? 2 and nil.nil? and therefore, the precedence is left to right ... I.e. Method argument is 2.

Anyway, the better question is why on earth would you write statements like this?

Omitting method parenthesis is only useful for code readability. However, your statements are hardly readable and makes one pause over the code and think about it more than he should. If I was to review code like this, I would definitely fail the code review due to poor readability.

In fact, many style guides explicitly state that most methods with arguments should be parenthesized (is this even a word ;). For example: Ruby style guide

Rado
  • 8,634
  • 7
  • 31
  • 44
  • 1
    I agree with you. This was in a code review and when I asked about it, I tried testing it out and discovered this behavior and I just wanted to gain understanding about the precedence of method arguments. I don't use `and` ever and I knew that the code as it was with `&&` would not work so I was curious about why it worked with `and`. – jshort Jan 26 '15 at 18:02
  • Yep, using this code in production would be mental, but it does make an interesting discussion, which I think was point – maniacalrobot Apr 17 '15 at 15:20