afongen
Sam Buchanan's weblog.

On Method Calls and Messages

Rubyists talk about methods calls as sending message to objects, a notion that I understand is inherited from Smalltalk. It always seemed a little strange, but I could accept it as an odd quirk ("Bah! I understand method calls!") and move on to writing code. This is unusual behavior for me, since normally I try to understand a language on its own terms. Now, though, I think I finally grok all this talk of messages, thanks to A Little Ruby, A Lot of Objects, an incomplete book in the style of The Little Schemer. And as it turns out, terminology matters.

class Dog
  def speak
    "Woof!"
  end
end

fido = Dog.new

Calling the speak method on fido (fido.speak) is really sending a message to the fido object. When fido receives the "speak" message, it knows to invoke the Dog class's speak method. It answers, or returns, with the String "Woof!"

Yeah, that doesn't seem too special, does it?

But here's the thing. In Ruby, everything's an object. 2 is an object of type Integer. 2 + 5 in Ruby is really saying, "Send the message "+" to the object 2, along with the parameter 5." That is, 2 + 5 is convenient shorthand, syntactic sugar for 2.send("+",5) (which is, by the way, valid Ruby). 2 receives the message and invokes its + method, passing 5 as a parameter. It responds with 7.

Okay, this is still not seeming very special. Doesn't this just muck up the discussion? Sure, it's neat that 2 is an object, but what do you gain from all this talk of sending messages?

I'll tell you where it finally clicked for me: polymorphism. I'm not sure why, but for some reason polymorphism is often a tricky concept for beginning programmers. Couched in terms of sending messages to objects, it's crystal clear (at least to me :). You can send the same message to different objects, each of which will invoke the appropriate method of its class.

class Cat
  def speak
    "Meow!"
  end
end

garfield = Cat.new

With both fido.speak and garfield.speak, we're sending the message "speak" to the object. fido receives the message and invokes its speak method, and garfield invokes its own speak.

+ does different things for Strings and Integers. This is commonly called operator overloading.

2 + 5 == 7
"Abe " + "Lincoln" == "Abe Lincoln"

The message is the same: "+" — but the methods are different. Ah ha!

And now I finally understand duck typing in relation to polymorphism. It should have been obvious earlier, but I never thought of it in that way (probably because I figured that polymorphism wasn't that tricky, so I didn't think about it). Dave Thomas's explanation of duck typing is fairly clear. In Ruby, types are defined by what objects can do rather than their class.

When I write

  fred << "dog"

in Ruby, I don't care whether fred is a String, a File, or an Array

What matters instead is whether fred can respond to the message "<<".

(If you're a programmer who only knows Java or C#, by now you're probably freaking out. That's okay. It gets easier.)

So talking about method calls in terms of sending messages to objects starts to make sense. I get a better (or at least different) sense of what's happening behind the scenes, and what otherwise can be abstract concepts become a bit more concrete and useful. I'm probably still missing something, but I feel closer.

If you missed the implicit recommendation of A Little Ruby, A Lot of Objects, let me make it clear now: it is a fine read, highly recommended. And now I want to go read The Little Schemer.