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
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 “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.