Methods and Parentheses

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.

Optional Parentheses

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

Required Parentheses

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.254.44