Ruby allows parentheses to be omitted from most method invocations. In simple cases, this results in clean-looking code. In complex cases, however, it causes syntactic ambiguities and confusing corner cases. We’ll consider these in the sections that follow.
Parentheses are omitted from method invocations in many common Ruby idioms. The following two lines of code, for example, are equivalent:
puts "Hello World" puts("Hello World")
In the first line, puts
looks
like a keyword, statement, or command built in to the language. The
equivalent second line demonstrates that it is simply the invocation
of a global method, with the parentheses omitted. Although the second
form is clearer, the first form is more concise, more commonly used,
and arguably more natural.
Next, consider this code:
greeting = "Hello" size = greeting.length
If you are accustomed to other object-oriented languages, you
may think that length
is a
property, field, or variable of string objects. Ruby is strongly
object oriented, however, and its objects are fully encapsulated; the
only way to interact with them is by invoking their methods. In this
code, greeting.length
is a method
invocation. The length
method
expects no arguments and is invoked without parentheses. The following code is equivalent:
size = greeting.length()
Including the optional parentheses emphasizes that a method invocation is occurring. Omitting the parentheses in method invocations with no arguments gives the illusion of property access, and is a very common practice.
Parentheses are very commonly omitted when there are zero or one arguments to the invoked method. Although it is less common, the parentheses may be omitted even when there are multiple arguments, as in the following code:
x = 3 # x is a number x.between? 1,5 # same as x.between?(1,5)
Parentheses may also be omitted around the parameter list in method definitions, though it is hard to argue that this makes your code clearer or more readable. The following code, for example, defines a method that returns the sum of its arguments:
def sum x, y x+y end
Some code is ambiguous if the parentheses are omitted, and here
Ruby requires that you include them. The most common case is nested
method invocations of the form f g x, y
. In Ruby, invocations of that
form mean f(g(x,y))
. Ruby 1.8 issues a warning, however, because the code could also
be interpreted as f(g(x),y)
. The
warning has been removed in Ruby 1.9. The following code, using the
sum
method defined above, prints
4
, but issues a warning in Ruby
1.8:
puts sum 2, 2
To remove the warning, rewrite the code with parentheses around the arguments:
puts sum(2,2)
Note that using parentheses around the outer method invocation does not resolve the ambiguity:
puts(sum 2,2) # Does this mean puts(sum(2,2)) or puts(sum(2), 2)?
An expression involving nested function calls is only ambiguous when there is more than one argument. The Ruby interpreter can only interpret the following code in one way:
puts factorial x # This can only mean puts(factorial(x))
Despite the lack of ambiguity here, Ruby 1.8 still issues a
warning if you omit the parentheses around the x
.
Sometimes omitting parentheses is a true syntax error rather than a simple warning. The following expressions, for example, are completely ambiguous without parentheses, and Ruby doesn’t even attempt to guess what you mean:
puts 4, sum 2,2 # Error: does the second comma go with the 1st or 2nd method? [sum 2,2] # Error: two array elements or one?
There is another wrinkle that arises from the fact that parentheses are optional. When you do use parentheses in a method invocation, the opening parenthesis must immediately follow the method name, with no intervening space. This is because parentheses do double-duty: they can be used around an argument list in a method invocation, and they can be used for grouping expressions. Consider the following two expressions, which differ only by a single space:
square(2+2)*2 # square(4)*2 = 16*2 = 32 square (2+2)*2 # square(4*2) = square(8) = 64
In the first expression, the parentheses represent method invocation. In the second, they represent expression grouping. To reduce the potential for confusion, you should always use parentheses around a method invocation if any of the arguments use parentheses. The second expression would be written more clearly as:
square((2+2)*2)
We’ll end this discussion of parentheses with one final twist. Recall that the following expression is ambiguous and causes a warning:
puts(sum 2,2) # Does this mean puts(sum(2,2)) or puts(sum(2), 2)?
The best way to resolve this ambiguity is to put parentheses
around the arguments to the sum
method. Another way is to add a space between puts
and the opening parenthesis:
puts (sum 2,2)
Adding the space converts the method invocation parentheses into
expression grouping parentheses. Because these parentheses group a
subexpression, the comma can no longer be interpreted as an argument
delimiter for the puts
invocation.
18.227.10.162