Ruby Quickes #4

Methods & Expressions

Consider:

def foo(x)
puts x * 2
end
puts foo 5 # → 10
puts foo(5) # → 10
puts foo (5) # → 10

Now consider:

def bar(y, z)
puts y + z
end
puts bar 1, 2 # → 10
puts bar(1, 2) # → 10
puts bar (1, 2) # Exception! --> syntax error, unexpected ‘,’, expecting ‘)’

The first time I saw this error raised, I was thrown off by the occurrence of ‘,’ thinking that ruby is now complaining about using a ‘,’ in between the arguments. This error was useless in explaining any issues I had with my code.

But because the ruby parser works in a very systematic and predictable way, I knew the error is not what it seems to be, and I wore my researching hat to find some answers. The reason turned out to be simpler than what I expected.

To understand the reason behind the exception appearing in the second method (the one with 2 arguments) and not with the first method (with 1 argument), it is necessary to understand the way how ruby works with methods arguments.

When calling a method in ruby, ruby expects arguments to be passed directly after the method name. An exception to this rule would be if the method is using default-values as arguments or even any arguments.

Passed arguments can be values or expressions, and as you might know, expressions in ruby can be surrounded by () to distinguish them and give them higher precedence in parsing.

Taking all above into consideration, when calling:

foo (5)

the argument (5) is considered a valid ruby expression.
However, with:

bar (1, 2)

the space between the method name and the arguments expression, gives ruby parser the wrong impression to parse the expression and extract the first argument value (first argument since the method expects 2 arguments).

But the expression contains an unexpected ‘,’ making it an invalid ruby expression, which raises a Syntax Error.

So, the problem here is not the usage of an expression, but the invalidity of that expression used, regardless of whether you intended to pass it as an expression.

To prove the correctness of this explanation, try this:

puts bar (1) , (2) 
# --> 3

However, if you try this:

puts bar (1) 
# --> ArgumentError: wrong number of arguments (1 for 2)

Simple but tricky, isn’t it?