
Alan Kay: Smalltalk is not about objects, it’s about messaging (1998) - pcr910303
http://lists.squeakfoundation.org/pipermail/squeak-dev/1998-October/017019.html
======
derefr
I think the key insight of Smalltalk can be grasped just by thinking about how
Smalltalk does branching. A line from the GNU Smalltalk tutorial:

    
    
        mybool ifTrue: [ ^ 2 / 4 roundup ]
    

The outer part of this expression reads “send a closure expression, as the
message ifTrue, to the receiver mybool.”

Keep in mind, this `mybool` could be anything! It just so happens that there
are two runtime objects, `true` and `false`, that satisfy the “Boolean
interface” (consisting of messages ifTrue and ifFalse) the way you’d
expect—with `true` running any closure passed in an ifTrue message, and
`false` running any closure passed in an ifFalse message. (For those of you
who know combinatory logic, these objects are essentially the K and SK
combinators.)

But consider that you can create your own object that implements this
interface—with whatever arbitrary logic you like—and substitute it for a
Boolean as the value of `mybool`, and no code will be able to tell the
difference.

This is what is meant by “computation as messaging.” Branching is a request to
an opaque “branch-evaluating object.” At each step of computation, you’re not
getting the _runtime_ to compute—you’re getting your _objects_ to compute. The
_objects are the computers_ , and the _messages are the instructions to those
computers_!

~~~
golergka
That sounds very interesting. How are return values treated under this model,
though? Is the object you send the message to obligated to send something
back, synchronously?

~~~
AllegedAlec
By default, each message call returns the result of the last expression. the '
^ something ' syntax is used to explicitly return a value.

~~~
bonzini
No, the default return value is self if the last statement is not
"^expression".

~~~
AllegedAlec
Yeah, I'm apparently a complete idiot and forgot basic syntax of a language I
have been playing around with for two years...

EDIT: This is not sarcasm. I am an idiot and he is right.

------
mntmoss
Something I have gotten more attuned to over time is the importance of the
message format - i.e. the medium - in defining the message.

That is, the way in which the message is specified changes the classes of
errors and development challenges one might encounter. If function arguments
are positional you get positional errors; if they are named you enter the
business of defining many more types. Messages may return a different version
of themselves(e.g. arithmetic) or a different category of message. The later
in time the message is delivered, the more it has to carry around its own
context. And when a message has unbounded scope it has unbounded complexity.

And like with a lot of things, there aren't silver bullets. Many things can be
defined as a single enumerated value. Sometimes tuples are nice, sometimes
records are nice. Sometimes the problem expands to the point where you have to
have a message with a little computer inside it - but when that happens it's
usually not for the purpose of any specific task, it's to add a layer of
programmability into the system.

~~~
rektide
Lovely post! Here here!

I've toss in cap'n'proto & surely others who let you write messages that talk
about still outstanding messages. Still short of referring to full on streams
in your messaging.

[https://capnproto.org/rpc.html](https://capnproto.org/rpc.html)

There's hx-uri that allows for referring to other http messages, which I think
could fulfill this in http.

[https://github.com/martinthomson/hx-uri](https://github.com/martinthomson/hx-
uri)

Here's to expanding the medium! Let the hypertext ever hyper.

~~~
DonHopkins
Thanks for pointing that out! I'd heard of Cap'n'Proto but didn't realize how
cool it was. Pipelining promises is incredibly useful! I'll check it out more
deeply now.

When I first heard of it, maybe I was initially skeptical because of the name,
having been traumatized years ago by Cap'n Software Forth on my Apple ][,
which John Draper developed to implement SleazyWriter while incarcerated in
the Alameda County Jail.

[https://archive.org/details/EasyWriter_Capn_Software_John_Dr...](https://archive.org/details/EasyWriter_Capn_Software_John_Draper_1979_Program)

>EasyWriter was a word processor first written for the Apple II series
computer in 1979, the first word processor for that platform. It was written
by John Draper's Cap'n Software, which also produced a version of Forth, which
EasyWriter was developed in.

>Draper developed EasyWriter while serving nights in the Alameda County Jail
under a work furlough program.

[https://news.ycombinator.com/item?id=14245590](https://news.ycombinator.com/item?id=14245590)

~~~
hhas01
Interesting. Hadn’t heard of Cap’n’Proto. A clever idea, although I do wonder
if it’s being too clever for its own good, being unnecessarily restrictive.

Dr William Cook (who designed much of Mac OS’s “RPC-plus-queries” IPC model)
explored a more generalized approach where whole self-contained chunks of
behavior can be sent across the wire for remote evaluation. As I recall, his
Batches model uses a “safe” subset of familiar JavaScript operations, but any
behaviors could be supported as long as they are guaranteed to terminate.

[http://www.cs.utexas.edu/~wcook/projects/batches/index.htm](http://www.cs.utexas.edu/~wcook/projects/batches/index.htm)

There’s nothing inherently magical about this: it’s just a carefully-
restricted form of remote execution where the client-supplied “code” to be
executed is incapable of doing nasty things like access restricted APIs or
lock /blow up the server with infinite loops or stack overflows. Beyond that,
it’s just a question of whose CPU you want to burn more, and how much time you
want to spend bouncing between them.

Thinking about it from a JavaScript or C mindset will make your head ’splode,
but for Lispers (of which Smalltalkers are a spinoff) it’ll be a big fat “how
obvious”. Be nice to see it further pursued.

------
thdrdt
There are so many models based on the ideas of Kay. But I got the feeling that
the actor model (Carl Hewitt) is closest to what Kay meant. Am I right?

~~~
mathgladiator
I think so, I'm accidentally building an actor centric programming language
and it is a magical way of building stuff.

~~~
bsaul
how do you handle persistence ? i’m trying to design a system at the moment
and i feel like actors are great until you have to deal with persisting state
to a database ( at which point the idea of having millions of independant
process each hitting your database to save and load their state look like a
disaster)

edit : i misread your post, thought you were designing a system, not a PL...
maybe you can still answer my question ?

~~~
ProfHewitt
Actors should be inherently persistent unless no longer reachable.

~~~
bsaul
What i mean by persistent is : what is the best practice to save an actor’s
state so that it can be properly restored in case of a crash without loosing
information.

I think i’m still not clear on how you would design a transactional system (
such as order & paiement processing ) with actors in a way that won’t make it
look like a microservice based system ( aka : one per subtask, fetching info
from a db for each incoming request, and storing the result in a db in the
end)

It seemed to me actors had to have a more fine grained context ( such as one
per order), but in that case i’m wondering how it’s supposed to handle saving
its state regularely so that no information on the order processing state is
ever lost

~~~
ProfHewitt
Excellent question! But your question seems to make the unfounded assumption
that application programmers should be in charge of restoring crashed Actors.
Instead, an Actor System should restore Actors as best it can based on
recordings that it has. Applications must be made resilient against any and
all kinds of inconsistencies that will pervasively arise.

~~~
bsaul
Do you know any resource i could read that would explain how all that is
supposed to work out in practice ?

I've never heard of an actor system able to automatically respawn actors with
their previous state (the whole system would look like a tree of cached data,
each layer responsible for saving the leafs under it, with a huge "persist to
DB" on top , wouldn't it ?). Does erlang OTP do those kind of things ?

Edit: also, are you Prof "Carl" Hewitt ? The one that invented actors ? I'd be
honored you found a question of mine about actors excellent...

~~~
mathgladiator
This is what I am building. I'm building a database of actors that are free
agents in a way.

The key insight is that an actor is a tiny VM and you just need to make the VM
state durable.

~~~
bsaul
I see many challenges :

\- not all states transitions need to be durable. If performance matters
you’ll have to get your actors to call something like a « saveState » from
time to time, otherwise every single property change is going to have an
overhead in terms of performance.

\- what does « durable » mean ? Surely, just having the state of an actor
saved in the memory of the supervisor isn’t enough. If the two are on the same
server and the server shuts down, it’s game over. You need a « persistence »
service / actor, but that thing is going to have to persist the state of all
the actors in your system. I don’t see how that can work if you’ve got
millions of actors running in parallel.

~~~
ProfHewitt
Durability is a matter of degree. Lowest is to record in RAM. Next is
persistent local storage. After that comes storage on other machines.

------
noughtme
Every time this comes up it makes me want to learn Smalltalk, but the current
tooling/IDEs don’t seem to have been kept up to date. Is it possible to learn
Smalltalk without a Smalltalk-specific IDE? Or, is there a relatively small
current language that is similar to Smalltalk?

~~~
e12e
Smalltalk was always a system first, language second. That said, if you want
to ignore half (not all!) of what makes Smalltalk interesting, there's always
GNU Smalltalk ("Smalltalk for people who can type"):

[https://www.gnu.org/software/smalltalk/](https://www.gnu.org/software/smalltalk/)

There's the free/open Pharo ("Squak for grown-ups"):
[https://pharo.org/](https://pharo.org/)

(Recently featured on hn in the guise of smalltalk on truffle/graalvm
[https://news.ycombinator.com/item?id=21735782](https://news.ycombinator.com/item?id=21735782)
)

And commercial offerings like Gemstone:

[https://gemtalksystems.com/products/gs64/](https://gemtalksystems.com/products/gs64/)

The recently open sourced dolphin: [http://www.object-
arts.com/gettingstarted.html](http://www.object-arts.com/gettingstarted.html)

~~~
ljm
To add to this comment; if you use Pharo, the impressive part is right in the
first-run tutorial. It gives you the basics but you have to write the code to
update the environment to give you the next/previous buttons for each step.

You can run whatever code you want in those windows, but just by finishing the
tutorial you'll have an idea of what you're getting into.

It's on my backlog of things to toy with, along with Prolog. And after playing
with Objective-C long enough I quite enjoy the syntax.

~~~
Gene_Parmesan
I can definitely highly recommend Prolog for playing. I found it to be a mind-
opener in the same way learning Scheme for the first time was a mind-opener.
Programming with predicates/relations is extremely powerful.

As a teaser, consider a predicate Concat(X, Y, Z). In Prolog, capitalized
identifiers are considered as unbound variables. There aren't return values;
instead, you compute via unification.

So we can approximate the idea of a list concat funtion by entering something
like `Concat([1, 2], [3, 4], X).` The Prolog evaluator will answer that X must
be [1, 2, 3, 4] in order for the predicate to hold true. Looks like a standard
function with a quirky way to provide an out param.

But these are predicates, not functions. Concat's internal logic defines a
logical relation among the various values. This logic holds no matter which
values you leave unbound. So here are some other things you get for free:

`Concat(X, Y, [1, 2, 3, 4]).` -- this will, in turn, iterate through all
possible values of X and Y that make this predicate true. Thus Prolog will
give us X: [], Y: [1,2,3,4]; but also X: [1], Y: [2,3,4]; and so on.

`Concat(X, [3, 4], [1, 2, 3, 4]).` -- this will give us X: [1, 2];
alternatively, it will give us the answer 'no' (sort of equivalent to false)
if [3, 4] is not some tail of the provided list.

`Concat([1, 2], [3, 4], [1, 2, 3, 4]).` -- will give us "yes", for true.

This is a simple example, but now perhaps the potential power of Prolog is
more visible. Imagine the possibilities -- for instance, a constructed grammar
can tell you not only if a given candidate sentence is valid, but it can also
(in theory) generate every single valid sentence in turn.

~~~
ljm
I've been feeling this out through the Adventures in Prolog book. It's also a
fascinating insight into how SQL engines work and what it means to write
declarative code.

I've had an idea for a prolog side-project for a while, but just haven't
learned enough yet to know how I could implement it. In my mind, reserving a
slot in a calendar or otherwise finding the next best opportunity is a valid
use-case.

------
kitd
The way messages are constructed in Smalltalk is one of its delightful
features. It seems so obvious to 'template' a message with the replaceable
parts being the parameters. Typical methods a la C++ or Java look so clumsy in
comparison.

It would be nice if there was a way to construct something similar around
actor-based systems on the JVM.

~~~
senderista
I’m very disappointed when I see new languages ( _cough_ Rust) not even
consider named arguments. The added readability at call sites just seems like
a no-brainer to me.

~~~
simias
The only counter-argument I've heard was that it has the consequence of making
the argument name part of the API (i.e. changing the name would be a breaking
change, so all parameter names of exported functions "leak" into the public
interface). That always seemed like a very minor drawback to me, I too would
appreciate to have named arguments in Rust.

~~~
Matt3o12_
It seems more like a feature to me. Sometimes parameters change slightly and
you will never notice it until you re-read the docs. So if the change is
explicit I can go look at it during compile time and not be surprised by it
during runtime.

Of course there are occasions where the name is unfortunate (typo, ambiguous
name or incorrect term) but the docs could mention it and it would not be the
end of the world.

~~~
simias
I agree, although I haven't done enough work with languages using named
parameters to really judge how inconvenient they can become in practice.

It seems like most naming issues could be alleviated by allowing the developer
to provide aliases, this way you can change the preferred parameter name while
still keeping the old one around for backward compatibility.

------
Animats
Nah. It's about objects. Messaging is when you send a message off to the vasty
deep and hope for a reply. A Smalltalk message is a function call that has to
return.

Most of the issues around messaging come from waiting for answers. Hence
callbacks, futures, async, retries, timeouts...

Good discussion of this back in 2012.[1]

[1]
[https://news.ycombinator.com/item?id=4788926](https://news.ycombinator.com/item?id=4788926)

~~~
lonelappde
I think Alan Kay knows what Smalltalk is about.

He uses messaging to mean interfaces and protocols of communication.

~~~
Animats
Ranks of "Message oriented":

Rank 1: Polymorphism. You can "send" a message to an object. You don't know or
care exactly what the object does. Other than the polymorphism, the "message"
behaves just like a function call. It will definitely be handled by your
target object, and it will definitely return instantly with a response. The
compiler might even be able to inline this function call.

As seen in: Pretty much every OOP language.

Rank 2: Messages as first-class values. It's possible to write a function that
forwards all incoming messages to another object, based on some logic. The
caller does not know what will happen to the message. However, the message can
be expected to be handled instantly, and it may respond instantly (if it does
have a response).

As seen in: Objective-C, Smalltalk

Rank 3: Asynchronous messaging. When sending an outgoing message, it might be
placed in a queue and handled at a later date. The message does not return a
result instantly, so agents must have some other mechanism (such as including
a "reply to" address) to be able to talk back and forth. From the perspective
of the caller, it's a bit like putting a message in a bottle and watching it
drift off to sea.

As seen in: Erlang, message queueing libraries.[1]

 _“When I use a word,” Humpty Dumpty said, in rather a scornful tone, “it
means just what I choose it to mean—neither more nor less.” “The question is,”
said Alice, “whether you can make words mean so many different things.” “The
question is,” said Humpty Dumpty, “which is to be master—that’s all.”_

[1]
[https://news.ycombinator.com/item?id=4788926](https://news.ycombinator.com/item?id=4788926)

~~~
galaxyLogic
> Rank 3: Asynchronous messaging. When sending an outgoing message, it might
> be placed in a queue

Arguments of a Smalltalk message can be "blocks" which are function-like
objects. The receiver of a message carrying a block as argument can put the
block into a list/queue and evaluate it any time in the future.

So that would seem to qualify as "asynchronous messaging" to me.

~~~
inopinatus
Blocks are closures, so they are bound to the sender's environment. If we
accept the definition given above they'd thereby fail the "message in a
bottle" test.

~~~
galaxyLogic
Not sure what exactly is the "message in a bottle" -test and why would we need
one?

I think it is a limitation of "bottle-mail" that you can not easily reply to
the message. Of course sometimes all you have is a bottle and a piece of paper
and the sea around you :-)

------
discreteevent
The other bit of that comment is also very insightful:

"I would say that a system that allowed other metathings to be done in the
ordinary course of programming (like changing what inheritance means, or what
is an instance) is a bad design. (I believe that systems should allow these
things, but the design should be such that there are clear fences that have to
be crossed when serious extensions are made.)"

------
ProfHewitt
Below is the fundamental axiom for Actor events (i.e. communications:

    
    
       ∀[S:ActorSystem, P predicateOn Event<S>] // For every ActorSystem S and every predicate P on events of S
        (∀[x:Primordial<S>] P[Creation[x]] // If P holds for the creation event of every primordial of S
         ⋀ ∀[e:FromOutside<S>] P[e] // and P holds for every event from outside S                       
         ⋀ ∀[e:Event<S>, e1:ImmediatelyFollows<e>] // and for every event of S 
               P[e]⇒P[e1]) // if P holds for the event, then P holds for each immediately following event
            ⇒ ∀[e:Event<S>] P[e]  // then P holds for every event of S
    

See the following for more explanation:
[https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3459566](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3459566)

~~~
elegaphant
I have an applied math background. What resources are recommend to understand
the symbols used here?

~~~
trobertson
The base notation is from formal logic. A (dense) overview of first-order
logic can be found on this wikipedia page:
[https://en.wikipedia.org/wiki/First-
order_logic](https://en.wikipedia.org/wiki/First-order_logic)

It's much nicer to get slowly walked through it with a textbook, but I'm
blanking on the name of the book I used.

~~~
elegaphant
Thanks trobertson. This may be what I need.

So, may I presume that the notation of (Prof) Carl Hewitt’s Direct Logic is
consistant with that of First-Order Logic?

~~~
ProfHewitt
Actually, the notation used above is for strongly-typed higher-order theories.

See the following:

[https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3418003](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3418003)

[https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3459566](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3459566)

------
mpweiher
Objective-Smalltalk ( [http://objective.st/](http://objective.st/) ) is a
newish smalltalk that was very much inspired by this very message (no pun
intended). And by Mary Shaw's work on software architecture, and, and...

So what might make a good metasystem? The ones we have are usually too
specific, too concrete, the metasystem for this particular language, sort of
like having a "types" rooted in concrete machine types (cough, C, cough).
Smalltalk solved this for the type-system, with the root being something
abstract, "Object". If you apply the same idea of creating a hierarchy to the
metasystem(s), you come up with something along software-archtitectural ideas
of component (procedures, methods, objects, filters, programs) and connector
(calls, message-sends, pipes, variable access, ...).

And it turns out that this gives you parsimony, great power, and pretty darn
good security of meaning.

------
seltzered_
A great visual example of messaging / sharing between two <s>apps</s> tools is
in "Alan Kay's tribute to Ted Nelson at "intertwingled" fest":
[https://youtu.be/AnrlSqtpOkw?t=607](https://youtu.be/AnrlSqtpOkw?t=607)

------
matchagaucho
Passing a single, immutable object as a parameter to a method, and replacing
several native parameters, is a common "what-if" comment I make in code
reviews.

It's not 100% the intention of Smalltalk messaging, but it's in the spirit of
"objects as messages".

------
bjornjaja
Does anyone know how this would relate to Qt signals/slots?

------
adamnemecek
It's about messaging and also loose coupling, referentiality, resources etc.
It's about being able to reference by some reference(UUID) rather than by
values.

This idea gives rise to contexts.

It's the difference between graphs and trees.

It's the difference between linear logic and classical logic.

In some sense, heap allocated objects work like this. The main problem is that
you can't relocate objects.

Rust's interior mutability is about this as well.

ECS[0] is about this.

[https://en.wikipedia.org/wiki/Entity_component_system](https://en.wikipedia.org/wiki/Entity_component_system)

------
mbrodersen
... which is why Erlang is perhaps the _only_ truly OO language used in
production today (using Alan Kay's definition of OO).

------
qwerty456127
Obviously. That's so sad OOP went a completely wrong way ever after.

------
paulcole
As a dev, I grok that smalltalk is all about messaging but I find that it
bores me to discuss the trivialities of sportsball with marketing or business
people.

~~~
grzm
> but I find that it bores me to discuss the trivialities

Then don't. There are plenty of other submissions on HN, and if you don't see
any you find worth discussing, submit some you do.

~~~
paulcole
I see I’m not the only one who didn’t read the article!

~~~
coldtea
Many people here have read the same case (OO as intended by AK and Smalltalk
being not about Objects but about messaging) made in different outlets from
Alan Kay over the years (I've read it over 10 times in various forms,
including 2-3 videos).

It has also been posted on HN for over 10 times, and a few times Alan Kay
himself was commenting here too.

So it's not like everybody needs to read this particular "TFA" to jump into
the discussion, or that it's that bad if they missed some specific reference
you've made to the content of this particular article...

