Operator Overloading in Ruby


I really like the fact that Ruby has operator overloading. In many cases this feature is not very fitting in a language, but in Ruby it definitely has its place. So what’s the difference? Why do people generally say that operator overloading in C++ is a bad thing, and that Java shouldn’t have it? I believe the main reason is static typing. When you have static typing and combine that with a verbose language, operator overloading doesn’t really fit in. You can’t create DSL looking API’s out of the language since the line noise usually make such efforts futile. And then you’re left with only the bad parts of operator overloading.

In Ruby on the other hand, it fits very well. It actually makes sense to be able to redefine and add operators since there are many places where your code can be made much more readable with it. Of course, you always have to be careful and not go over board with it, but when used riht it improves readability to a large degree. A typical example of nice use of overloading is in Hpricot:

doc/:html/:body/:p/:img

Here the division operator have been overloaded to make it possible for you to write XPath like search strings beginning on a parsed Hpricot document.

Another place I really like is in the Ruby core library where the call method is usually overloaded as []. This makes sense if you think about it – in most cases the objects you can call on will take parameters and return a result based on the parameter. This can be mapped quite neatly to an Array or Hash containing values that are returned, and in fact you can imagine swapping out this restricted usage of an Array or Hash to something that you can call things on.
If the [] method is all you used for access, duck typing makes it easy to send in a Proc instead of an Array or Hash.

Another reason using [] can be nice, is since Ruby doesn’t let you override (). If you want to emulate that kind of behavior, [] can act exactly the same if you want it to.

In the Ruby core, the more useful things that implement [] is Array and Hash, of course, UnboundMethod, BoundMethod, Proc and Continuation. This means that you can do something like proc{ puts “hello” }[] if you feel like it.

There are lots of other nice operators to overload in Ruby, though. Some of the better ones are unary + and unary -, all the common arithmetic operators, ||, &&, |, &, <, >, <=, >=, ~, =~, **, ==, === and a few others. The two things missing here is the ! and friends, and (). But of course, adding () wouldn’t really work with the Ruby language. ! on the other hand should be overridable.

So, you should use operator overloading in Ruby, but be careful that it makes sense and actually gives you a good abstraction, not just something “cool”.


9 Comments, Comment or Ping

  1. Anonymous

    I agree that operator overloading in Ruby is generally a good thing. However, I think that your contention that the unary not operator (!) should be overridable is a bad thing. Ruby considers all objects except nil and false to be true for the purpose of conditionals. Allowing an object to decide that it is false (if !obj …) but not true would invalidate all sorts of otherwise reasonable logic about objects. The only case for overloading not I can think of is making RSpec a tad more readable.

    I rather like the way Scala handles operators; namely that they’re just method calls with a precedence determined by the first and last character. Such a view fits well with everything being an object, and Scala’s type-system allows them to compile very efficiently in the “non-overloaded” case as well.

    October 6th, 2007

  2. Konrad

    As far as I know, C# offers operator overloading with quite a success despite its static typing.

    October 6th, 2007

  3. Jim Weirich

    The && and || operators are not overloadable, mainly because they provide “short circuit” evaluation that cannot be reproduced with pure method calls.

    October 6th, 2007

  4. Robin

    I’m glad Ruby allows to overwrite the == operator, in Java I’m always in danger to write s == “bla” when I
    mean equals.

    Python allows you to overwrite the () operator, so that in every place where a function is expected, you can also provide a class with the __call__ method, which can be used to track state.

    October 6th, 2007

  5. Maxim Kulkin

    It would be nice if Ruby in new versions supported the following behaviour:

    when some object is used as boolean expression (e.g. “if foo then”), call to_b (or to_boolean) on it. This would allow creating special proxy objects that could represent e.g. false expression (for now Ruby considers all non-nil-or-false objects to be true). Default implementation for Object#to_b would be ‘true’, False and Nil classes – ‘false’. That would maintain backwards compatibility.

    The other thing, it would be nice if foo( … ) would transform into variable-or-method lookup and then call to value.call( … ). I don’t see a reason why this should be hardcoded.

    October 7th, 2007

  6. Greg

    The bit about static typing doesn’t make sense to me as it stands. I’m guessing from the line noise bit you meant to say “explicit typing”?

    October 8th, 2007

  7. Anonymous

    Funny how you say operator overloading is not useful in statically typed languages, and then go on listing features (Xpath-like operators, function-collection equivalence) that Scala has out of the box.

    Scala has some powerful DSL creation abilities, some of which would not be possible without static typing (i.e. user-defined control expressions) in a C-like syntax.

    October 8th, 2007

Reply to “Operator Overloading in Ruby”