Yes! This is something it took me a long time to internalize but is something I absolutely love about Objective-C. Regardless of any technical differences between message passing and method calling, there was a real shift in how I thought about the process. When I started thinking about object interaction as message passing, it made me write better encapsulated code. I'm not sure exactly what it is, I think that part of it is that to me a “message” sounds more lightweight than a method call, or that it more strongly stresses the concept that objects are communicating, but it a different way of seeing the problem.
It's funny you should say that. I have the exact opposite intuition: message passing is substantially slower than method calls, especially statically bound method calls in a statically typed, compiled language.
You're right that message passing is a different way of looking at things; but obviously it's something different to method calls. Delegation, for one thing, is much easier with message passing, as are other strategies, like default implementations, remoting (never mind how poorly RPC scales), etc. On the other hand, getting two objects to communicate over a private channel can be more awkward, as they need to share pre-arranged references, rather than simply being friends / package / internal visibility, or similar visibility override.
An interesting aside to this thread is that it was started as a debate over class vs prototype based inheritance by Steve Dekorte. Steve went on to create Io four years later. A great example of putting your money where your mouth is.
Ugh. This reminds me of a week or so go when I referred to a hypothetical object "responding to a message" and my coworkers looked at me like I was insane.
They thought I meant an MQ type message, and were completely unfamiliar with the concept of message passing.
I gave an Intro to Ruby class the other day, and made a point of emphasizing the idea of message passing. I also gave a quick intro to `method_missing`.
It pains me when people spend a fair amount of time coding Ruby, and then encounter metaprogamming and dynamic method invocation, and because of their wrong preconceptions they think it's deep, dark, super-genius hackery.
Unfortunately it gets clumsy to always say, "passes the message 'foo'" instead of "calls 'foo'", but if you can make the point early and toss in some reminders along the way the idea may stick.
That is actually the very conference Kay is talking about in the mailing list post, where he "took some pains … to remind everyone … it is not even about classes."
Yes, it's messaging that really forces clean encapsulation. Otherwise, you can end up in getter/setter hell, where everybody still knows everything about everything, even though all data is private.
Getter and setter methods on objects are like OK and Cancel buttons in dialogs. Just because it's uniform industry "best practice" doesn't make it not completely retarded and obscurantist.
From this point of view, Clojure, a functional language which explicitly rejects OOP as most people have come to know it could be considered OO. State changes in Clojure are done by sending a function and optionally some values to a reference type. The main goal is to support concurrency, but the more principled approach to state inherently discourages the use of complex mutable data structures.
Anybody who is interested in Alan's point of view and want to know more or want to work on the systems we design based on "messaging all the way down" like our startup Morphle (see http://siliconsqueak.org ) should email us at aart5@knoware.nl (minus the '5'). The current work Alan is doing can be found at vpri.org
What is the essential aspect that distinguishes a message from a call? According to Wikipedia, it's that the arguments are deep-copied, but that is not what happens in Smalltalk, AFAIK. It's also contradicted in another section where it says the arguments are "usually" copied. I would have thought the important part was late binding, which is indeed a requirement but apparently not divisive.
Edit: If this is any indication then I'm prepared to declare "message passing" a heisenterm, with no formal definition across all contexts:
One of the major differences, from a programming point of view (as opposed to implementation) is that with message passing, you can pass any message to an object, even if that object doesn't know how to handle it.
Cocoa makes extensive use of delegates (not sure if these are similar to .net delegates) for handling unrecognised messages, which makes adding custom behaviour to classes possible without subclassing.
Rails is (in)famous for making use of Ruby's method_missing to implement all sorts of funky stuff.
A method call is two separate messages. One going to the object with the parameters, and another with the result. Note that even void-return functions involve two messages; in that case, the return message simply indicates completion of the function that is bound to the method.
Thinking in terms of messages passing makes you think of the objects in a proper way.
Objects just aren't structs with methods on top: you can create lots of those without them ever being objects in the proper sense. Objects are a separate concept.
Multiple or predicate dispatch object systems take the view that objects are structs without methods in them. Methods are just open conditionals: by defining a new method implementation you add a clause to the conditional.
e.g.
type Animal
type Lion < Animal
type Elephant < Animal
type Giraffe < Animal
method encounter(Animal, Animal)
def encounter(Lion a, Giraffe b):
// eat it
def encounter(Lion a, Lion b):
// fight
Is equivalent to:
type Animal
type Lion < Animal
type Elephant < Animal
type Giraffe < Animal
def encounter(Animal a, Animal b):
if(a is Lion && b is Giraffe):
// eat it
else if(a is Lion && b is Lion):
// fight
else:
raise NoApplicableMethodError
Languages with predicate dispatch usually allow you to define your own predicate classes:
And they allow you to add predicates to methods themselves:
def encounter(Lion a, Giraffe b) when isHungry(a): eat
def encounter(Lion a, Giraffe b) when !isHungry(a): walk away
This is much more powerful and simpler than message passing, IMO.
It's closely related to pattern matching in languages like Haskell, but that's usually not allowed to span multiple modules or files. And algebraic data types are closed, making it much less useful.
That's interesting. I've read a paper about it, but I don't remember exactly. Is it implemented in GHC?
Type classes are more powerful in some ways, but much less powerful in other ways. There is some overlap, but type classes dispatch only on the compile time type whereas this dispatches on run time predicates.
This view is probably prevalent because C++ more or less does (and did even more in its early days) promote objects as structs with methods and some other fanciness on top, and C++ was probably the first really widespread OO language.
Replying to myself: an interesting aspect, I think, is that this isn't solely a failing of C++ (though C++ has plenty wrong with it). This model of structs-with-methods had already started appearing in C, in the form of APIs built around sets of functions that all operated on the same struct, which was passed as a void* as the first parameter of all the functions (void* for encapsulation purposes); see the pthreads API, for example. So in some ways it's also a consistent, and even sort of naturally arising, model of OO, sort of an organic development out of structured programming, where structs and associated functions serve a main role in the structuring. It's of course a quite different notion of OO from Kay's message-passing, so maybe should have a different name, if it were an ideal world?
In fact, in C++ structs and classes are the same thing, only struct declarations starts with public visibility by default and class declarations starts with private visibility by default.
That's their only difference in C++.
And so instances of structs and instances of classes are the same thing in C++ too.
You will even sometimes see member functions defined on structs.