Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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



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


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.


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 :-)


There may be forms of messaging where the "medium" surrounding messages is more like an aether -- sorta like photons in space. And the addressing to objects super loose. I don't think it needs to be so strongly receiver-bound.


I would stipulate that go channels are closer than erlang. I.e. Erlang is actors, and actors are CSP. Go does CSP directly.


Synchronized requesting in Communicating Sequential Processes (CSP) [Hoare 1978] proceeds as follows: “Such communication occurs when one process names another as destination [to receive a request] and the second process names the first as source for [the request] ... [in order that providing the request] is delayed until the other process is ready [to receive the request].”

Synchronized requesting x with request r (i.e. x!r) can be implemented as follows using a 2-phase commit protocol: x.synchronize[Implements Provider ⟦provide ↦ r⟧] so that after x has received a synchronize message with parameter Implements Provider ⟦provide ↦ r⟧, x can get r from the parameter using a provide message (cf. [Knabe 1992]). Synchronized sending x a request r (i.e. x!r) can be algebraically reduced (which is a primary requirement of communication in the π-calculus [Milner 1993]) because x is provided with r without arbitration by Implements Provider ⟦provide ↦ r⟧.

Synchronized requesting (i.e. x!r) has the following significant costs in time, communication bandwidth, and robustness by comparison with unsynchronized Actor requesting (i.e. x.r):

1. The requester must wait for the receiver’s provide message in order to provide request r.

2. After receiving a synchronize message, the receiver must wait for the request r to be provided (meanwhile holding up processing of other requests).

3. Both the requester and receiver must be online concurrently for communication to take place.

Unsynchronized requesting (i.e. x.r) cannot in general be reduced using an algebraic equation as in [Milner 1993] because in general, the request must go through arbitration in order to be received. Although algebraic reductions may be elegant mathematics, synchronized requesting is not widely used in large software systems because it is slower, uses more communication bandwidth, and is less robust than asynchronous requesting (especially for IoT).

According to [Milner 1993]: “An important task is to compare it {π-calculus based on algebraic reduction using synchronized requesting} with Hewitt's Actors; there are definite points of agreement where we have followed the intuition of Actors and also some subtle differences, such as the treatment of names {i.e., request providers}. More generally, the π-calculus is a formal calculus, while the Actors model, in spirit closer to the approach of physics, sets out to identify the laws {i.e. [Hewitt and Baker 1977] expanded into the uniquely categorical axiomatization in this article} which govern the primitive concepts of interaction.”


Hi Carl. Pleasure to read your comments.

I’ve tried applying Actors to my C++ projects and always hit 2 issues in Actor model:

1) the need for synchronous access. As long as a single thread is accessing each Actor sequentially, then there is no issue with locking an Actor for synchronous access (barring deadlocks). I feel dirty locking Actors, but it solves many practical problems.

2) sharing resources requires a language which understands locks, since even Pony’s reference capabilities doesn’t solve real world performance issues. Ideally, each shared resource would have a paired lock whose usage the compiler verifies.

Both issues deviate from Actor model purity since they require locks, but I cannot resolve real world performance problems without them.


I feel woefully inadequate among present company, but nonetheless offer my 2 cents:

There is a fundamental performance tradeoff between sequential vs concurrent computation, because concurrency always requires some form of communication. Locks are difficult to reason about, but allow for shared resources. I've found the actor model to be so useful because it allows me to trade the ability to share resources for a more intuitive form of communication, message passing.

Regarding your 1st point: Each actor is itself a sequential computer. You can't share an actor between threads any more than you could share a Turing Machine between threads. When designing actor systems I imagine a 1:1 mapping between threads and processors. The concurrency is happening in userspace.

Regarding your 2nd point: It's my feeling that current actor model implementations are only suited to a narrow range of problems characterized by massive concurrency, a lack of shared state, and flexible time requirements. If any of those aspects are missing, I've learned to look elsewhere for a solution.


Thanks!

Unfortunately, C++ has many issues implementing Actors because of problems with regions of mutual exclusion with holes.

See the following: https://papers.ssrn.com/abstract=3418003


Hi, and thank you for all your intriguing messages and thoughtful arguments!

I've heard that Actors don’t have an identity, only addresses:

https://medium.com/@alex_karaberov/everything-you-always-wan...

>Each actor has an address. In various implementations an address can be a direct physical address (e.g. MAC address of the NIC), email, memory address, some id and so on. Multiple actors can have the same address, and one actor can have multiple addresses. There is a many-to-many relationship here. Address is not a unique identifier of the actor. Actors don’t have an identity, only addresses. So, when we step back and look at our conceptual Actor Model, we can see and use only addresses. We can not tell whether we have one actor or multiple ones even if we have one address, because it can be a proxy for the group of actors. All we can do with an address is send it a message. Address represents capability in the Actor Model. Mapping of addresses and actors is not part of the conceptual Actor Model although it is a feature of implementations.

So I was wondering if you're the same Carl E Hewitt as https://news.ycombinator.com/user?id=carlehewitt and as your user name professes, or if either or both of you are actors? ;)

And have you ever played Santa Claus?

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


Don, you are very welcome!

Alexander Karaberov's article (linked above) is an important contribution.

You are correct that since an Actor can have many addresses, it is not clear what it would mean for an Actor to have an identity."

PS. Excellent SNL Santa :-)


PS. If you employ locks correctly, you can do regions of mutual exclusion (with holes) in C++ :-)


Would Proxy objects in JS be an example of Rank 2? And a proxy object that returns promises an example of Rank 3?




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

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

Search: