It all Starts with the liver...
Let's take a break from programming for a while and talk about biology. More specifically, cells. I promise this will tie into message passing, just stick with me.
This is a repost from programmingwords.com. It’s a blog about about different computer science topics explained in a simple, understandable way. Check it out if you’re interested in compsci, compilers or programming languages! :)
We usually think of our bodies as machinery of bones and organs, pushed and pulled by muscles and neatly wrapped in a layer of skin. But when you zoom in, you'll see a giant sea of about 10 trillion cells that are all chaotically floating around.
There are about 200 different types of cells in your body, each with their specific function. For instance, your kidney is made up of kidney cells, all working together doing... well... whatever a kidney does. (I'm not a biologist.)
Each of these cells is about 100,000 times smaller than you, but somehow this soupy mess of cells manages to work together to move my fingers while I type this sentence. The key, like in all teamwork, is communication.
Cells talk to each other through a process called cell signaling. One type of cell signaling is called endocrine signaling, and you can think of it as Slack, but for cells: It lets remote cells work together.
Let's look at a concrete example: You're stressfully working overtime to meet a deadline. Because you're stressed out, right above your kidneys, the cells of your adrenal gland start releasing a molecule you're familiar with: Adrenaline. Adrenaline is a pretty clear message that says "things are about to get ugly".
Adrenaline travels through your bloodstream all the way to your liver. Your liver cells have receptors that can receive adrenaline. Once they receive the message, they change their behavior in response.
See, the liver is like a storage facility for glucose, your body's primary source of energy. If things are about to get ugly, your body best have enough energy. So, liver cells respond to the message by producing more glucose, giving your muscles enough energy to fight or flight.
Adrenaline is just one of the many molecules that can be sent as a message. Cells communicate by sending and receiving these molecules. A receiving cell has specific receptors which can read those molecules. Once a message is received, the cell makes changes according to the message.
If you take the previous sentence and replace "cell" with "object" you'll get message passing.
What does a liver have to do with programming?
Message passing is a way parts of your program can communicate with each other. With message passing, each object acts as an independent cell. The only thing an object can do to communicate with other objects is to send a message.
In a mainstream OOP language like Java or C#, you'd have objects which define their methods that you call to make changes within those objects. For instance, the following code would call a method called setNumberOfUsers
on an object called userStore
:
userStore.setNumberOfUsers(3)
Message passing adds another layer of abstraction to this process. With message passing, you'd achieve the same effect by sending a message to the object:
sendMessage(userStore, "setNumberOfUsers:3")
Instead of having a predefined set of methods to call on the object, you send the object an arbitrary message. Whether or not the object responds to that message is up to the object.
In the above example, the message is a simple string. There's no concept of "defined" methods and the compiler won't check that the method exists. Instead, you send a string and it's up to the object to read and respond to the string.
The biggest difference between mainstream OOP and this approach is who owns the methods. In mainstream OOP languages, methods live on the class. To add a new method, you have to create a new (sub-)class.
Message passing takes this one step further by letting the objects themselves decide how to interpret and respond to messages, and which messages to respond to. Two instances of the same class can respond differently to the same message.
This adds a layer of flexibility when modeling your program. Did you ever start writing a class and called currently non-existent methods that you will implement in the future? I do this all the time. With message passing, calling a not-yet-implemented method wouldn't result in any errors. The message would get sent, but simply ignored by the receiving object.
This achieved a level of decoupling that isn't possible with languages like Java. Two pieces of code are decoupled when a change in one doesn't result in having to change the other. With message passing, removing, adding or renaming messages doesn't result in compiler errors. Objects are decoupled to the point of not even depending on the method names.
Mainstream OOP languages ask of you to model your software ahead of time, creating classes and methods before you even use them. Message passing adds enough flexibility that the design of your code can emerge organically and change as needed.
The benefits of message passing are similar to the benefits of dynamic typing. In fact, message passing pretty much requires a dynamically typed language, or at least a lack of type safety in a statically typed language.
A concrete example
Alan Kay is widely credited for being one of the people who coined the term "object-oriented programming". What he invented wasn't what's in Java or C# today, instead, the cornerstone of his OOP was message passing.
Alan Kay's idea, like most ideas, came from a soup of discoveries that all intertwined to create Smalltalk — the programming language that popularized OOP, the most popular programming paradigm ever.
But Smalltalk looks different from Java. First of all, it's dynamically typed. That noise you hear right now is all the Java developers shuddering. It's dynamically typed because it uses message passing. Think about it, you can't have static predefined types if each object can respond to an arbitrary set of messages.
I'm going to show you a bit of Smalltalk now and it will probably look different than any language you've seen. Smalltalk was released around 50 years ago, so its syntax is different from the C-based curly-braced languages we're used to.
We'll start by declaring a variable called num
. Variable declarations are surrounded by |
. (...for whatever reason.)
| num |
You'll notice there are no type specifiers here -- remember, Smalltalk is dynamic.
We'll then assign a value to this variable:
num := 42.
Like a lot of older languages, Smalltalk uses the more mathematical :=
for assignment instead of the now more common =
. To end a statement, we'll use a dot instead of a semicolon, just like this sentence*.*
Now we're going to raise 42 to the power of 2.
num := num raisedTo: 2.
In a C-based language, this might look like num = pow(num, 2)
.
Instead, Smalltalk uses message passing. Here, raisedTo: 2
is a message that's sent to the object num
. Smalltalk calls the named portion of the messages a selector (raisedTo
), which can have their arguments, in this case, the number 2.
Language designers like message passing because of its recursive nature. Once you have message passing, you can build the whole language on top of it. For instance, an if/else
expression can be nothing more than sending an ifTrue
message to a Boolean object.
numberIs42 := (num = 42)
message := numberIs42
ifTrue:[ 'answer' ]
ifFalse:[ 'not the answer' ].
The above line assigns "answer" to message
if num
is equal to 42. num = 42
evaluates to a boolean object, which we can send messages to. The ifTrue:ifFalse:
message has two arguments which are blocks of code, in this case, each returning a string.
Instead of if
and else
being special keywords that are built into the syntax of the language, here they're nothing more than simple messages being sent to an object.
Even creating classes is nothing more than sending messages to an object!
Object subclass: 'Square'
instanceVariables: 'a'
This is how you create a class with the property a
. This bit of code sends a message subclass:instanceVariables:
to a globally defined object called Object
.
Java has to scan through all of your classes and their methods and then compile the code by binding a method call to a block of code. Smalltalk doesn't do any of this at compile-time, instead you send a message to Object
to create a class while the program is running. That's right, you can create new classes in the middle of running your code.
Smalltalk's equivalent of Java's methods would be the messages objects of this class can receive. Let's add a couple of those.
a: newA
a := newA
a:
^a
area:
a * a
init:
a := 1.
You'll notice there's no properties, methods or fields -- it's all just messages. A "getter" is a message called a
that, upon receiving, returns the value of a. Similarly, a setter is a message that includes the new value as part of the message. Even the "constructor" is just a plain old message called init
.
Smalltalk, as created by Alan Kay back in 1972, is a lot different than the one above, and even the one above is almost 40 years old. Not a lot of people use Smalltalk, but, through an accident of fate, its spirit still lives on among programmers in a language called Objective-C.
Objective-C was created around the same time as C++ and for a long time, these two languages were competitors for the title of the dominant OOP language. Eventually, as you might have guessed, C++ won out.
But Objective-C lives on mostly because of Steve Jobs. When he left Apple, he founded a company called NeXT and created an operating system based on Objective-C. 12 years later, Apple bought this company and installed Steve Jobs as their CEO, who moved all of their software to NeXT's operating system. The result is that, more than 20 years later, macOS, iOS and other Apple's platforms are built on top of a huge Objective-C codebase.
Objective-C is not the only modern language with message passing, though. Message passing is a core feature of Ruby and Python, and can be used in various other languages with libraries.
The Real OOP?
Throughout this article, I've been juxtaposing mainstream OOP with message passing. But, as you've seen, the term was coined for message passing. As Alan Kay puts it:
I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.
The big idea is "messaging” [...].
If message passing is what started OOP, how come nobody talks about message passing in this context anymore? None of my college OOP classes mentioned message passing. OOP is always presented as a combination of polymorphism, inheritance, encapsulation and abstraction. These all exist in Smalltalk, but mostly as a symptom of message passing, not baked into the language.
The truth is, around the same time Smalltalk was being designed, another language called Simula was being developed in Oslo, Norway. This language was also an OOP language (in fact, probably the first OOP language), even though it wasn't called that at the start. It didn't have message passing but instead relied on something called abstract data types.
If you worked with any mainstream OOP language, you already know what abstract data types are: classes. Simula introduced almost all of the features we consider part of OOP today including classes, objects, inheritance and even garbage collection.
The biggest difference between Smalltalk and Simula is that Simula used types. Even today, when we have a huge number of advanced linters and tools to help with dynamic programming languages, a lot of programmers still prefer statically typed OOP languages, especially for larger projects. Back then, the tooling around dynamic typing was even less developed, so it stands to reason people found types more productive that the wild west of sending messages and hoping someone, somewhere will receive them.
A lot of CS-nerds will keep reminding you that Alan Kay didn't have C++ in mind when he thought of OOP. Standing here more than 30 years later, I don't think it matters. Terms are there to be useful in communicating an idea, and it seems clear that "OOP" means Java more than it means Smalltalk, even if Alan Kay didn't imagine OOP that way.
Which isn't to say Smalltalk is a failure. Languages, sometimes, are like films. Indie filmmakers are making impactful films like Tarantino's Reservoir Dogs, that a few people see, but their influence is felt for decades. Mainstream films like Avengers, though, are watered-down combinations of those influences, a sort of common denominator that almost everyone will like.
Languages can sometimes be the same way. Even though Java doesn't have message passing, it was still heavily influenced by Smalltalk. In fact, almost all OOP languages were influenced by Smalltalk. Without Alan Kay, the language you program in would probably look different.
This is why it's important to encourage idealistic, vision-driven programming languages. They might look weird, but rest assured there are ideas in them that will surely spread into mainstream languages later down the line.
Note: In mathematics, message passing is known as the actor model. This is a very important model for concurrent programming, but it's a story for another post. :)
References:
An email from Alan Kay describing how he got to Smalltalk's design
http://www.purl.org/stefan_ram/pub/doc_kay_oop_en
Another email on OOP as per Alan Kay
http://lists.squeakfoundation.org/pipermail/squeak-dev/1998-October/017019.html
The Early History of Smalltalk, Alan Kay
(A paper on the history of Smalltalk)
http://www.metaobject.com/papers/Smallhistory.pdf
This is a repost from programmingwords.com. It’s a blog about about different computer science topics explained in a simple, understandable way. Check it out if you’re interested in compsci, compilers or programming languages! :)
Top comments (0)