- OOP is message passing
- The interactive environment
- Surprising things about Smalltalk
- Did Smalltalk achieve its goals?
- Failure of Enterprise Smalltalk
No longer true since Smalltalk-76, which has virtual method dispatch like Java. What you refer to is probably Kay's philosophy which is something else than the Smalltalk implementation we know today.
Can you elaborate on this because this has been bugging me for some time. I’ve heard Kay’s comment many times but I have never heard him give an explanation as to what practical difference it would make in the day to day task of software development, specifically with respect to Smalltalk 80. When I think of message passing I think of things like Kafka, message queues, ESBs etc. Where the producers and consumers of the messages are completely decoupled and the processing is asynchronous. But I’m not sure how this maps to a thread/proc local context where a caller of a function or method or the sender of a “message” expects a response.
Kay's view of object-orientation is "messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things" (quoted from http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...). This is quite different from what we associate with object-orientation today (objects, classes, inheritance, virtual methods, etc.), and how it was implemented e.g. in Simula 67, or in Java. Kay's view has similarities with Hewitt's actor model (see e.g. https://www.quora.com/What-is-the-difference-between-Alan-Ka...). A good source on how Smalltalk-72 was different from Smalltalk-76 is Ingall's 2020 paper (https://dl.acm.org/doi/10.1145/3386335). Smalltalk-72 indeed implemented a kind of message passing in that there were objects "sending" token streams to other objects which interpreted these streams; so there was indeed something like a "message", and there are similarities with message queues and parts of Kafka; message passing can be synchronous or asynchronous. Calling a method is not the same as passing a message; there is no message which has to be "interpreted", but the compiler knows the signature of the method and generates efficient code for calling it using a specific ABI. If methods from objects are called which reside in a different address space/process or even on different hardware, then method calls are dispatched over an IPC mechanism or even a network (like e.g. CORBA or some versions of ESBs); the network dispatch is technically message passing, but to the programmer it still looks like a local (synchronous) method call. The Smalltalk community instead prefers to talk about "message passing", even if it is implemented as plain in-process, in-memory method call. It is also notable that already Simula I (1962) had "active objects" (the Simula I objects were called "process") and there was the notion of events and queues.
You're talking about the internals and optimizations. Smalltalk still uses message passing as the concept, even if it doesn't send an actual a message for the recipient to parse under the covers.
That's how you can trivially have distributed objects, instances responsing to methods they don't directly declare and know about, etc.
Well, "dog" is just a name we give to a specific set of attributes, so no, the dog wouldn't still be a dog (in the sense that the word "dog" would not communicate what he is to another person).
In this case, even acceptaing post-76 Smalltalk doesn't implement "real" message passing unver the covers, we not only call it that anyway -- so one would be justified to say:
"real X is what we call X, not what originally we call X, or what the etymology of X implies"
but it also behaves like it. So one would be doubly justified to say it is (in the "if it walks like a duck, and quacks like a duck" sense).
In other words, in this, I think you're making the same mistake you accuse Kay of making with regards to OOP ("C++ and co is not real OOP" -- well, it is now, as that's what we describe as OOP nowadays).
"perform" is a method of the Object (i.e. Integer super) class, the argument is a symbol; this call just does a second method dispatch, i.e. "perform" does yet another dispatch on the Integer object and then calls the "factorial" method; so no, neither this is message passing; it's rather like Object.getClass().getMethod() and Method.invoke() in Java.
huh? That makes no sense to me (I must be missing something here).
'perform' is indeed a msg. The integer object doesn't need a 'perform' method in order to do something with that call. Its entirely up to each object to decide how it wants to deal with a msg. Including those msgs for which there isn't a corresponding method.
In other words, the caller has NO way of knowing (or enforcing) what the object its sending a msg to, does with that msg. Eg: based on certain runtime conditions, an object can reconfigure itself at runtime, and simply proxy certain messages to another object, potentially running on a different machine, and relay the results back.
Why should "perform" be a message? It's just a method of the Object class, which is the superclass of Integer. You can use my St80ClassBrowser and St80ImageViewer (see https://github.com/rochus-keller/Smalltalk/) to check the ST-80 source code and image if you want; there is a list of all selectors (i.e. method signatures) and the classes which implement them. Going up the class hierarchy when doing virtual method dispatch is a fundamental concept of all object-oriented implementations; in contrast to e.g. C++ this can be done dynamically at runtime in Smalltalk or Java (which is also called late binding). In contrast to Smalltalk in Java the class loader verifies that a method for the referenced signature actually exists; in Smalltalk you can try to dispatch any signature which can result in a call to the doesNotUnderstand method of the Object class; the same could also be achieved in Java with a custom class loader, but usually you want to avoid it.
As a counterpoint, I would suggest looking at Jeff McAffer's CodA project. It defined a group of 7 metaobjects to define the behavior of each object, six of them for message passing and one for accessing state. He couldn't patch the commercial VisualWorks virtual machine and used #doesNotUnderstand: tricks to make his prototype work. It wasn't fast, but showed that the semantics were correct. Here are the message passing metaobjects he defined:
- Send: prepares a message to be sent and negotiates with the receiver
- Accept: negotiates with the sender
- Queue: can save accepted messages to be handled later
- Receive: deals with queued messages
- Protocol: can associated the selector in a message with executable code
- Execution: knows how to used system resources to actually do what the message asked
The default metaobjects are 100% compatible with Smalltalk-80 base level code but his thesis show several interesting alternatives.
There is no doubt that you can implement a message passing system in Smalltalk, as you can with any Turing complete language. In Smalltalk instead of "calling a virtual method" people just say "sending a message". But it actually works quite similar like e.g. the Java VM. Params and receiver object are evaluated and pushed to the stack, then the method is looked up in the receiver class using the selector (which is an internalized string) and then calls the method with the given parameters (this lookup and call is called "send" in Smalltalk); the major difference is that in Java the verifier checks whether a method with the given name and signature actually exists in the class when it is loaded; but also in Java you can influence the dispatch as you described and e.g. create your own class loader.
While you can implement message passing on top of any language, as you said, I was talking about doing message passing under Smalltalk-80.
There are non messaging parts in Smalltalk-80, like assignment. The Self variant of Smalltalk goes quite a bit further in using message passing for everything.
>But there is also a pertinent body of knowledge that is taught and tested at universities, which includes an accepted terminology.
Well, speaking of universities, can you find a univercity-level course/book that doesn't characterize Smalltalk (post 76 too) as having message passing?
> how will looking at Smalltalk-80 source code show us what "true" message passing is?
Not at all; but you can look at the Smalltalk-72 source code.
> Do you mean like Erlang?
Examples of "true" message passing are e.g. SOAP or MPI. Erlang is an example where message passing is indeed part of the language; another example are Go channels.
My guess is that very few people care to learn anything about Smalltalk-72, and simply saying you mean something like SOAP or Erlang will clearly communicate what you mean by "true" message passing.
If your interest is point-scoring maybe say Smalltalk-80 is simulated message passing or faux message passing ;-)
Some of what we covered: