Hacker News new | past | comments | ask | show | jobs | submit login
Alan Kay on the misunderstanding of OOP (squeakfoundation.org)
119 points by chc on May 17, 2010 | hide | past | favorite | 30 comments



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.


Yeah, to me "message" makes me think of very heavy duty systems like MQ.


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.


We live in a world where programmers think of Java's Object model when they think of OOP.

Which is a crippled version of C++'s Object Model.

About which Alan Kay said: 'Actually I made up the term "object-oriented", and I can tell you I did not have C++ in mind.'

http://video.google.com/videoplay?docid=-2950949730059754521


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


And those of us who understand OOP are forced to suffer because nobody else does...


This is very timely, thanks! I'm still in the middle of reading http://gagne.homedns.org/~tgagne/contrib/EarlyHistoryST.html and this already answers one question that was floating around in the back of my mind in the first paragraphs.

I'll read the whole thing when I'm done with the other link (which is a really long and very interesting piece).


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.


Verbs!

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.


Usually people think "best practice" is "everybody does it this way".


Sad, but true. And this explains the state of the Linux desktop today: copied from Microsoft instead of inspired by Apple.


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.


This is exactly right. Clojure does not abandon what is good about OOP.


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:

http://stackoverflow.com/questions/43777/method-vs-message-v...


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:

    def Prime(n): // primality testing algorithm here

    def Foo(Prime n): ...
Or:

    type Rectangle height width

    def Square(Rectangle r): height(r) == width(r)
    
    def Something(Square x): ...
    def Something(Rectangle x): ...
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.


Yes. There's also the possibilities to have open data types in Haskell.

Also type classes, and being able to add instances for any type are closely related to your examples.


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.


I agree. About more powerful: The static approach allows you to dispatch not only on argument types, but also on return type.

A quick search reveals that there is some support for open data types in GHC, but I am not sure if it's more than an experimental feature.


> Objects just aren't structs with methods on top

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.


what is the proper way of thinking of objects that message passing yields (genuinely curious)?




Applications are open for YC Winter 2022

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: