Aaron Cohen
Aaron Cohen

Reputation: 132

Why does this Boolean statement in Ruby give an error?

This is probably simple, but I don't understand why this statement isn't valid Ruby code:

3.>5 || 3.>2 
SyntaxError: unexpected tINTEGER, expecting end-of-input

Why this one is:

3.>5 || 3.> #this seems nonsensical
=> false

And why by my book this one seems to give a misleading answer

3.>5 || 3.>(2)
=> false

Yet, this one gives the "right" answer

3.>(5) || 3.>(2)
=> true

Upvotes: 4

Views: 138

Answers (2)

matt
matt

Reputation: 79813

The confusion here is due to using . to make Ruby parse the comparisons as method calls, rather than the more normal binary operator such as 3 > 2. In Ruby operators such as > are ultimately handled as methods, but the parser has special cases to allow you to use the more familiar syntax.

If you imagine there is a method called gt on integers, and you rewrite your examples using it instead of > it might be clearer what it happening.

Your first example, 3.>5 || 3.>2, will be equivalent to:

3.gt 5 || 3.gt 2

which Ruby tries to parse as

3.gt (5 || 3.gt) 2

That 2 at the end is the unexpected tINTEGER that Ruby complains about.

The second example, 3.>5 || 3.> will be parsed as something like this:

3.gt (5 || 3.gt)

This seems nonsensical because we know that gt is really the binary operator > and that it should have a second operator. Since Ruby is parsing it as if it was a method it has no way of knowing how many arguments there should be. As far as the parser knows the gt method may not expect any arguments (we could have monkey patched > to not expect an argument). Since the evaluation of the expression 5 || 3.> short circuits to 5, the 3.> part is never executed so no error occurs.

If you write the same expression but without using ., the Ruby parser knows that this is a binary operator and will expect the second operator:

eval '3>5 || 3 >'
SyntaxError: (eval):1: syntax error, unexpected end-of-input
3>5 || 3 >
          ^

The last example, 3.>(5) || 3.>(2), would be parsed as:

3.gt(5) || 3.gt(2)

Because of the parentheses there is no ambiguity and it is clear that the 2 is an argument to the method call, so you get the correct answer.

Upvotes: 2

Phlip
Phlip

Reputation: 5343

Ruby is space sensitive and, unlike the syntax highlighter used in this website, Ruby employs "maximum munch" when parsing operators.

3.< is different from 3. <, because .< parses as "send the < message to the integer 3."

Add a space. Better, never leave a dangling dot, for just this reason, and code 3.0 < 1.

Next, 3.>5 || 3.>(2) parses as 3.>(5 || 3.>(2)), because of Ruby's magical disappearing parentheses. Follow your style guide, and add spaces around almost all binary operators. The few idiomatic ones where you shouldn't are ., .&, .., **, etc...

Upvotes: 3

Related Questions