Written on January 29th, 2008.

My criticism on the Ruby programming language wasn’t as well-received as I had hoped. Especially the idea of requiring parentheses in method calls got loads of negative feedback.

I have been rethinking the idea for a while, and I’ve come to the conclusion that requiring parentheses is the wrong answer to a problem I didn’t even explain well.

Making Ruby Ugly

A Ruby variant where method calls require parentheses would quite simply be ugly. I’ll prove it by giving a couple of examples.

Getters

“Get” accessor methods are quite clean without parentheses. Even though an accessor is a method, you never treat it like a method. A sample getter could look like this in Ruby:

address_book.people

When parentheses are required, you’d change that line and write something more like this instead:

address_book.people()

In this case, parentheses make the method call explicit. Without parentheses, it feels as if you’re simply accessing a property, and not calling a method. With parentheses, you’re explicitly calling a method.

Usually, explicit is better than implicit, but I believe this is an exception. A method name should be a verb, not a noun—after all, a method is a series of instructions. I would rather write:

address_book.get_people()

This code is understandable: it calls a get_people method which will fetch the people and return it. This piece of code is quite a bit longer than the original, though. Especially when chaining such getters, code gets ugly:

address_book.get_people().get_last().get_first_name()

Setters

Requiring parens would make Ruby-style setters impossible. Imagine doing this:

person.first_name=('Denis')

These kind of setters are definitely not as pretty as their parenthese-less brothers. In fact, I think the parens here do not make sense, and it would probably be less confusing to fall back to a more explicit “set”:

person.set_first_name('Denis')

And Ruby’s charm is absent.

Ruby DSLs

A Ruby on Rails “has many” declaration would look like this:

has_many(:people)

The real beauty of Ruby DSLs is that method calls don’t look like method calls. A parenthese-less has_many doesn’t look like a method at all. Adding parentheses simply renders this ugly, and I actually believe it is a confusing construct—method names should be actions. If parentheses were required, I’d rather write:

set_relationship(:people, :many)

Requiring parentheses would make writing Ruby DSLs impossible.

The Real Problem

The real problem, which I totally failed to explain properly, is that method calls with implicit self receiver are indistinguishable from local variables.

Take a look at this piece of code:

foo = bar

bar can either be a method or a local variable. Similarly, there can either be a local variable named foo, or a method named foo=. By simply looking at this line, there is no way to know for sure what foo is and what bar is.

Now take a look at this:

@foo.bar = @baz.quux

bar= definitely is a method, and so is quux. Both @foo and @baz are variables. There is no ambiguity.

Why This Bothers Me

There are two reasons why I dislike this kind of ambiguity.

The first reason involves easy syntax highlighting. There is no way to correctly highlight method calls in Ruby, unless the entire source file is re-parsed every time a change is made, which is terribly slow.

The second reason is accidental performance loss. To illustrate, imagine having a class with a data method that reads data from the disk, formats and returns it. In another method in that class, you could be using data, treating it like a local variable instead of a rather expensive method.

A Better Solution

Requiring parentheses is a solution, but probably one of the worst ones.

One better way of making local variables and methods look different is to require an explicit self receiver. For example:

# foo and bar are methods
self.foo = self.bar

# foo is a method, bar is a local variable
self.foo = bar

# foo is a local variable, bar is a method
foo = self.bar

# foo and bar are local variables
foo = bar

If you think typing self over and over again is too much work, then maybe you’ll prefer omitting the explicit self receiver (thanks to apeiros for the idea):

# foo and bar are methods
.foo = .bar

# foo is a method, bar is a local variable
.foo = bar

# foo is a local variable, bar is a method
foo = .bar

# foo and bar are local variables
foo = bar

Problem solved.