2

The following code results in an error

Example 1

if params[:id] == '2' || params.has_key? :id
  abort('params id = 2 or nothing')
end


syntax error, unexpected tSYMBEG, expecting keyword_then or ';' or '\n'
if params[:id] == '2' || params.has_key? :id

However, switching the conditional statements || adding parentheses works 100%.

Example 2

if params.has_key? :id || params[:id] == '2' 
  abort('params id = 2 or nothing')
end

Example 3

if (params[:id] == '2') || (params.has_key? :id)
  abort('params id = 2 or nothing')
end

Can anyone explain to me why Example 1 will result in an error ?

Thanks

4 Answers 4

4

Your problem is happening at:

params[:id] == '2' || params.has_key? :id

which can be simplified to:

:foo || some_method :bar

which causes the same error. This expression is in principle, ambiguous between

(:foo || some_method) :bar         (1)

and

:foo || (some_method :bar)         (2)

When an expression is ambiguous, it is resolved by other factors. One factor, operator precedence tells nothing here about disambiguating between (1) and (2). The next factor is linear order. Since || appears before argument application () (omitted) in the expression in question, the former applies before the latter. Therefore, the expression is interpreted as (1). Since (:foo || some_method) would then be parsed as an expression, there would be two expressions next to each other. That is ungrammatical, just as:

:baz :bar

is ungrammatical.

In fact, if you switch the order as:

some_method :bar || :foo

then, it will be interpreted as

(some_method :bar) || :foo

for the same reason, and syntax error will disappear.

Also when you resolve ambiguity by explicitly using parentheses to indicate argument application:

:foo || some_method(:bar)

then there is no ambiguity needed to be resolved, and the syntax error disappears.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the great explanation. This is a helpful link : techotopia.com/index.php/Ruby_Operator_Precedence
1

Your :id is a symbol in Ruby.

a = {'id' => 'a', 'value' => 'value'}

a.has_key? 'id'
=> true

a.has_key? :id
=> false

So you need to change your code:

if params[:id] == '2' or params.has_key? 'id'
  abort('params id = 2 or nothing')
end

Note: If you are going to use this code checking for key before checking for value makes more sense.

Note #2: Tested with :

params = {'id' => 'a', 'value' => 'value'}

if params[:id] == '2' or params.has_key? 'id'
  abort('params id = 2 or nothing')
end

and Ruby 2.0.0

Also check this question for more information about Ruby Symbols.

4 Comments

plus 1 for checking for key before value
Changing the code to your suggestion results in the same error.
@user2594899 I've changed the || operator to or and provided and example code.
0

It has to do with how Ruby evaluates that if statement.

Example 1 is like if (params[:id] == '2' || params.has_key?) :id

which resolves in an unexpected symbol error as you can see syntax error, unexpected tSYMBEG.

1 Comment

Thanks for replying. Why would it ignore the :id in example 1 ?
0

As guy says... the parser doesn't assume that the symbol is a parameter for the has_key? method

You can bypass the error by explicitly coding the parentheses

if params[:id] == '2' || params.has_key?(:id)

3 Comments

IMHO, that's a stupid assumption to make, considering that has_key ALWAYS needs a parameter ? 100% Agree that adding the parentheses will work, it's just confusing when you need to (best practices) parentheses and when you shouldn't.
ouch, for that I got downgraded? :) The parser doesn't necessarily know that has_key? needs a parameter.. it might be a user method. Off-hand I can't think of a legitimate construction of ` if condition_a || condition_b :symbol` so what the hey, it might be a 'bug' in the Ruby parser... I don't know if it's been reported as so to the ruby core team via redmine
Wasn't me that downgraded you ;) I don't have enough reputation points. @sawa answer seems legit, although I don't agree with how ruby parses that code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.