Actors have been around since the early 70s and have been influential in both language design and program design (Erlang most notably). The essence of an actor is that it encapsulates state change and forbids shared mutable state. Actor programs are – by definition – asynchronous message passing systems. Actors can model an email server and its client, either of which send new content to each other but are written and run separately. This explains actors “in the large”.
An actor – simply put – is a computation that on receipt of a message, can do any combination of these (or none at all):
– create a finite number of new actors
– send a finite number of messages
– change its behavior for processing the next message.
If any changes are requested, they all appear to occur at once, or none occur (much as in database transactions).
Messages can contain references to actors, and, in combination, actors provide a conceptual unification of Operating System privileges (“sandboxes”), control flow (there are no while loops), and networking (aside from latency, there is no functional difference between an actor running locally and one on another client machine halfway around the world).
while (*cp++ = *ep++) ; // copy string ep to cp
Data structures are interwoven into graphs, and once multi-core showed up, the complexity of which thread changes what with what impact elsewhere became untenable, although not for a lack of trying with locks, semaphores, and even Communicating Sequential Processing (CSP, which led to Go) monitors and channels. The key problem, especially in a spatially distributed program (email servers and clients, etc.) is that, as Einstein taught us, one can never know what state anything anywhere else really is in. Actors say: We know (from a message) what was true at the time the message was sent, but not whether it is currently true. This is a fundamental difference in philosophy with real world physics on the side of actors. In fact, quantum physics has been modeled with actors so, as some have said: “it’s actors all the way down” (not turtles!).
Functional languages like ML and Haskell take a different approach. Data structures are not shared, and neither are they mutable. Programs compute new values based on old values and new inputs. Reality kicks in, however, in that actual changes to the world go through a specialized operation (>>=) that is inherently single-core. Functional programs are very mathematical since they are based on simple aggregating clusters of data and code. HacktorScript uses immutable (unchanging) data structures at is core while allowing any actor to change the world, including from several cores “simultaneously”.
The last major category of programming languages includes logic programming, such as Kowalski’s Prolog (once thought to be the end-all) and its predecessor Planner from the 70s. More generally, constraint-driven language systems (5th generation) are modern descendents. A key idea here is that logical goal fulfillment can have side effects, such that when the temperature sensor goes above 90 and the thermostat is not set to 90, it could trigger a side effect like “call the fire department”.
Imperative, functional, and logic languages can all be implemented in actors. Dr Carl Hewitt (co-inventor of the actor model) has proven that actor math is more powerful than Turing Machines. Turing Machines, it turns out, do not process inputs!