💾 Archived View for dioskouroi.xyz › thread › 29369328 captured on 2021-11-30 at 20:18:30. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

Ask HN: If OOP is about message passing, why not sender.send(receiver, message)?

Author: revskill

Score: 29

Comments: 38

Date: 2021-11-28 14:52:56

________________________________________________________________________________

jasonhansel wrote at 2021-11-28 19:13:12:

I would argue (contra Kay) that OOP really isn't about message passing; an object is fundamentally a state machine, not an actor or a fiber. So it should really be:

thing_undergoing_state_change

.state_change(params)

amw-zero wrote at 2021-11-29 10:25:22:

This is an obligatory comment that you feel this way because of popular languages that have the OOP label that don't have much of any resemblance to what Kay intended as OOP.

To understand his vision more, look at Smalltalk. Messages are more than just re-branded procedure calls, they can be inspected and forwarded to other objects (i.e. delegation) for example.

AmpsterMan wrote at 2021-11-28 19:33:49:

I think you are exactly correct. The success of OOP thinking is actually one of the things I don't like sometimes; we are so focused on creating state machines with carefully crafted interfaces that we forget that we can have stateless functions as part of our state machines. In general, I wish we were more careful with only creating these state machines when the alternative is more complex, or when the problem domain is easily modeled by one.

streetcat1 wrote at 2021-11-28 15:57:53:

Yes. You miss polymorphism.

The reason for receiver.method(), is that the binding to the receiver is done in runtime and not in compile time. Hence, you can change the ACTUAL receiver object without changing the sender.

al2o3cr wrote at 2021-11-28 16:09:19:

While i think it should be

    sender.message(receiver, params)

Why do you think that? Not trolling - it's hard to understand what you might or might not be "missing" without understanding your thought process.

In the overwhelming majority of cases, "sender" is implied by context; objects do not send messages on behalf of other objects.

hedora wrote at 2021-11-28 17:51:32:

You might want to look at Barbara Liskov’s work on object oriented programming. It refined a lot of those concepts, and looks closer to modern OOP than Kay’s sender model.

https://arstechnica.com/science/2009/03/acm-gives-turing-awa...

https://en.m.wikipedia.org/wiki/CLU_(programming_language)

spacechild1 wrote at 2021-11-28 16:28:11:

I learnt that (from Alan Kay), OOP is about message passing

I just like to point out that Alan Kay has a very particular idea of OOP that doesn't match the current mainstream usage. None of the modern OOP languages are “object oriented“ in Alan Kay's meaning of the term.

Rendello wrote at 2021-11-28 16:46:22:

One sort-of exception is Erlang (and anything else that runs on the BEAM vm, like Elixir). It doesn't match Alan Kay's vision exactly, because the message passing is done a bit differently (for example it's asynchronous), but creator Joe Armstrong called it something like "the best of functional programming and OOP".

If you come from C++, Java, or other "OOP" languages, and look at Erlang, it's completely different than what you expect. In Erlang, the "objects" are less like mutable structs and more like functional mini-programs that can create new programs, pass messages, and fail as you would expect.

To get some perspective on both of their perspectives, here's "Joe Armstrong interviews Alan Kay":

https://www.youtube.com/watch?v=fhOHn9TClXY

dllthomas wrote at 2021-11-30 19:48:04:

> Joe Armstrong called it something like "the best of functional programming and OOP".

Though IIUC Armstrong only started doing that after others pointed out that it was OOP.

Lammy wrote at 2021-11-29 00:38:34:

> for example it’s asynchronous

Ruby also lets you build programs like this as of 3.0, using Ractor#send / Ractor::receive

https://docs.ruby-lang.org/en/master/doc/ractor_md.html#labe...

It’s still pretty new so a lot of the Gem ecosystem hasn’t caught up yet (e.g. C extensions need to be explicitly opted-in as Ractor-safe), but I built a new “MIME::Types” library replacement with it recently and have enjoyed very few teething issues:

https://github.com/okeeblow/DistorteD/blob/NEW%E2%80%85SENSA...

Zababa wrote at 2021-11-29 09:12:37:

I think Alan Kay's OOP is widely used, but not at the "program" level. From what I understand, according to Alan Kay, OOP is about message passing, late binding and internal state. This is the way lots of software works these days with JSON over HTTP, or protocol buffers, or something else. I think at some point people imagined that there would be a point where you could buy or use objects from other people to build your programs more efficiently. I think that's what happened, with some companies offering very specific objects (auth for example, or persistance), while other offer a library with everything you need (cloud providers). And we even "rediscovered" the concept of interface in a way with stuff like "compatible with the S3 API".

stevenalowe wrote at 2021-11-30 21:52:47:

Within the execution environment the sender is known (it’s the current object) and the verb “send” is generic and thus not informative so typing sender.send over and over is unnecessary

jecel wrote at 2021-11-29 20:33:57:

Imagine that you have three friends helping you with a task. You might give them these instructions:

Jack, clean the shelves.
    Helen, sort the reports.
    Lucy, turn on the printer.

You can see that the receiver of each message is the first thing in each line while the message follows it. That is the syntax of imperative expressions in English.

If your name is Kevin and you are the one sending on the messages, where is "Kevin" in the above text? And you sent three messages and yet there is not a single "send" command to be seen.

Here is a less trivial example:

Jack hire a carpenter build cabinet store reports.

This is not valid English, but is a valid Smalltalk-72 expression. A variation which would have the same result is:

((Jack hire a carpenter) build cabinet) store reports.

The first message requests that Jack hire a carpenter. The result of the message is a carpenter who is not named by us, but which we can tell to build a cabinet. The result of this second message is a new cabinet, which we did not name either but which can be asked to store the reports.

So Smalltalk got its syntax from English and that inspired OOP languages that followed.

dragonwriter wrote at 2021-11-30 15:28:53:

Am i missing anything ?

Conventionally, the send is always implemented _in_ the sender, so explicit sender makes no sense.

This is true even in Erlang as opposed to class based OOP, though there the syntax is:

receiver ! message

keeeeeeeem wrote at 2021-11-30 15:20:43:

You're missing nothing. Class based OOP is essentially a set of arbitrary ontologies forced upon you by library authors. Your interpretation is no more or less meaningful than the others.

amw-zero wrote at 2021-11-29 10:22:08:

You're taking a complicated subject and reducing it to talking about what amounts to be pretty superficial syntax. There's more to messaging than just how the syntax of sending a message - how do you represent messages? Call by value or reference? Is the call synchronous or asynchronous (e.g. Erlang)?

Also, in terms of syntax, why not:

send(receiver, sender, message)

Why is the act of sending tied to the subjects at all, and not the responsibility of the system itself?

the-alchemist wrote at 2021-11-28 17:05:29:

Great question! I've thought about this too, in my younger days.

All of this is IMHO:

* your examples are programming language specific. Python, C++, Java-ish, from the looks of it

* Alan Kay's OOP, as far as I understand it, is about /disconnecting/ the sender and receiver, and have them "communicate" via messages.

pornel wrote at 2021-11-29 01:08:33:

Kay’s favorite OOP language was Smalltalk:

receiver message:params

    condition ifTrue:[dog bark]

There isn’t an explicit sender here.

Order of arguments is just an irrelevant syntactic detail as long as only the receiver chooses the method implementation.

There is an alternative approach called multiple dispatch or multimethods where every function argument can be used to look up the appropriate method to call. It’s implemented in e.g. Julia.

mikewarot wrote at 2021-11-28 17:16:54:

Objects are records with a controlled interface, so that you don't have to see the internal details. This allows restructuring of the internals without disrupting the code that uses the objects. It is a fairly well understood mechanism for preventing unwanted side effects.

The interface is type checked, and the appropriate way set the type rules is to bundle them with the interface (and thus the object), not with the user code.

jolmg wrote at 2021-11-28 20:42:38:

Am i missing anything ?
sender.message(receiver, params)

It's the receiver that determines what messages they can understand, and the sender itself rarely has anything to do with the message apart from sending it. It doesn't make sense to make the sender an important part of the syntax for message-sending. By keeping the sender out of the syntax, the syntax of a particular call is the same no matter how the sender changes from moving the code around.

Also, writing it as receiver.message(params) follows English grammar of subject-verb-object ordering, allowing the code to read more naturally.

sender.send(receiver, message, params)

If you're asking about the use of the word "send", at least Ruby uses it, but it's receiver.send(message, params). That particular call does not follow English grammar, but you only ever use the "send" message when the message is variable. It's not common.

rgoulter wrote at 2021-11-28 16:54:32:

It could even be expressed as `(params message receiver)`, or `message; <params>.{{receiver}}` or whatever other syntax.

But it's going to be more thoughtful to explain what parts of programming or of software design or architecture are emphasised by different ways of arranging things.

`receiver.message(params)` puts an emphasis that it's the receiver which receives and acts upon the message. The receiver will conform to some kind of interface with which we can interact.

`sender.message(...)` seems completely bizarre to me. -- Some module's interaction with other things is where the interactions are defined? Sounds interesting if it works!

bee_rider wrote at 2021-11-28 17:06:22:

Hypothetically, you could design a language where methods aren't defined by the thing before the dot, but by the last argument, I guess? This doesn't seem like a very sensible thing to do, though.

hypertele-Xii wrote at 2021-11-29 20:51:16:

receiver.message(params)
sender.message(receiver, params)

The only difference here is that _sender_ is _implicit._ Since you are writing code in an object's context, the sender is _this_ object (a keyword in many languages).

srivathsaharish wrote at 2021-11-28 19:02:14:

I think you are right in thinking it must be sender based. But it might not sit well with dev ergonomics. But almost every actor based implementations do what you are suggesting in one form or the other

PaulHoule wrote at 2021-11-28 15:58:52:

The ‘sender’ is the code doing the call and the context. Most languages don’t let a method know who called it, so it is not a ‘full fat’ implementation of messaging which would be more like email.

gjvnq wrote at 2021-11-29 04:16:16:

Learn Smalltalk.

myObj 4 "this sends the number four to myObj. Yes, comments are in quotation marks"
  4 factorial "yep, numbers are objects too"
  0 + 4 "sends the 4 as a message to 0"
  myObj arg1: 1 arg2: 'a' "if you need more than 2 arguments you use keyword messages"

thesuperbigfrog wrote at 2021-11-28 17:30:37:

The Quicksilver word processor / desktop publishing system offered a user programming interface in lisp.

The Quicksilver lisp used object-oriented programming and most of the documents and desktop system were objects. Calling methods on those objects originally used a function called "tell" for message passing:

(tell object method parameter1 parameter2)

Later they deprecated "tell" in favor of:

(method object parameter1 parameter2)

rodrigosetti wrote at 2021-11-28 18:04:42:

I think usually the sender is implicit (the calling context) so it could me omitted.

Racket [1] has a non conventional syntax too.

[1]

https://docs.racket-lang.org/reference/ivaraccess.html#%28fo...

seanalltogether wrote at 2021-11-28 19:06:10:

This is effectively how all calls in Objective-C work. Everything turns into

objc_msgSend(receiver, message, params)

stevefan1999 wrote at 2021-11-29 05:59:31:

Well, at least that was how Smalltalk (which is what Kay does contribute to) works. And if you have actors, it also looks similar as well (when you pass a message to a mailbox).

toast0 wrote at 2021-11-28 18:59:12:

sender.send(receiver, message, params)

is really sending a message to sender with content {send, receiver, message, params}

If you want the receiver to know who the sender is, you need to pass that along in the message. Personally, I find that's easier to manage if it's explicit rather than implicit. If I want to send a message and have replies go to me, I'd say the sender is self or this or what have you; but if replies should go elsewhere, I can easily do that. With an implicit sender, you have to route the sending through the sender to get the reply to the right place and it adds considerable structual complexity.

steve_coral wrote at 2021-11-28 17:41:45:

Godot’s Signals work like this.

https://docs.godotengine.org/en/latest/classes/class_signal....

spacechild1 wrote at 2021-11-28 19:04:30:

FYI, the signal-slot paradigm has been introduced and popularized by Qt over 20 years ago.

https://en.wikipedia.org/wiki/Signals_and_slots

archsurface wrote at 2021-11-28 16:48:11:

I don't know the actual answer, but that would be a lot of useless typing.

bediger4000 wrote at 2021-11-28 16:22:58:

sender.send(receiver, message, params)

A lot of very bad corporate software has informal object-oriented-programming implementations that either look like this, or map to it directly.

aryehof wrote at 2021-11-28 17:54:16:

Look to the inventors of Object Orientation to learn what it is about. They won a Turing award for it after all. Hint: It wasn't Alan Kay.

jecel wrote at 2021-11-29 20:44:27:

Simula I was a huge influence on Alan, as was Sketchpad (a parallel invention of object oriented programming). But Simula was a hybrid language like the later C++, so in the issue about message passing syntax Smalltalk had a certain impact.

Simula-67 introduced inheritance, which Smalltalk-72 and -74 didn't have. Many people see it as a key OOP feature, which Smalltalk-76 added.

Kristen Nygaard, who with Ole-Johan Dahl had created Simula, was one of the creators of the very pure Beta programming language.

https://en.wikipedia.org/wiki/BETA_(programming_language)

This took the message passing syntax in a very different direction:

  message -> receiver