Among the language-level programming models for distributed systems, there are two prominent camps: those that view a distributed system as a collection of objects, and those that view it as a collection of actors (e.g., Akka, Erlang).
Both actors and objects are capable of receiving messages¹. In response to a message, an actor/object may (1) change how it will respond to subsequent messages, (2) spawn new objects/actors, and (3) send messages to other objects/actors. The difference between actors and objects materialises in how these aspects pan out.
(3) Sending messages to other objects/actors
Starting with (3), if we send a message, in the object model we eventually expect to get a reply. In the actor model we merely assume that our message has been received. It seems that the actor model comes with a less rigid assumption!
However, the weaker assumption comes at the cost of locality of error-handling: If a message cannot be delivered in an actor-based system, a supervisor ought to send a message to the originating actor, informing the actor thereof. This detaches the handling of a message-send error from the act of sending the message.
On the other hand, it relieves you from waiting around for some sort of response. It is natural in the actor model to go on and do useful work while you await a response. In the object model, this is achievable, but with a bit extra work: by leaving it to another thread to await the response.
We say that the object model is based on synchronous message-passing, while the actor model is based on asynchronous message-passing.
(2) Spawning new objects/actors
Continuing with (2), in the actor model, a spawned actor always executes concurrent to, and independent of the spawning actor. In the object model, this isn’t necessarily the case: objects may share data, and may share threads of execution.
Since there is no shared data, the actor model relieves the programmer from having to deal with potential data races — they cannot occur. In the object model, data races must be avoided using low-level synchronization techniques. Object programmers may choose to pay this price for the ability to implement locally-efficient concurrent data structures — where the actor model fails to deliver.
As a consequence of the differences outlined for (2) and (3), in the actor model, the arguments sent along in a message must be a deep-copied. In an object model, arguments may be sent by reference, leaving it to subsequent requests to fetch the remaining data, if needed. This aspect of the object model also has some benefits for multi-threaded programming, and may reduce network costs, but can also make latency hard to reason about.
(1) Changing the response to subsequent messages
Finishing off with (1), in the object model, an object may typically only change its internal state, and not swap itself out with another object. In the actor model, swapping an actor out with another, in response to a message, is rudimentary.
This difference is negligible: The behaviour of an object may depend on a collection of variables stored inside the object. The object may modify all of these variables, in response to a method call, changing its behaviour completely.
At the same time, it is uncommon to declare objects that fundamentally alter their behaviour in response to a method call. That is, to declare objects that change the set of methods, or the set of variables they possess. This sort of programming is only common when declaring objects in property-based languages, where objects are not statically declared, but constructed at runtime².
(0) Handling the message queue
One final difference between message-passing in the actor and object models is whether an actor/object responds to any given message, and when.
Due to the concurrent nature of distributed systems, if there is a high demand for the services of an actor/object, it will build up a queue of messages to handle. Actors and objects differ in how they handle this queue.
In the actor model, the actor can selectively respond to some messages, while dropping, or putting off others. It may even add the message back to the queue, by re-sending the message to itself. In the object model, the object must linearly respond to all messages, in the order in which they were received.
Footnotes
- Alan Kay, a pioneer of object-oriented programming, pointed out in 1998 that “The big idea [ed. of OO] is ‘messaging’…The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.”
- This leads to the supposedly unpopular conclusion that programming in an actor-based language (e.g., Erlang), is similar to programming in a property-based language (e.g., JavaScript or Python), with the notable exception, that actors concurrently run independent of each other.