Monday, April 13, 2009

Objects as Actors ?

Tony Arcieri, creator of Reia, recently brought up an interesting topic on unifying actors and objects. Talking about Scala and his disliking towards Scala's implementation of actors as an additional entity on top of objects, he says, it would have been a more useful abstraction to model all objects as actors. Doing it that way would eschew many of the overlapping functions that both of the object and actor semantics have implemented today. In Reia, which is supposed to run on top of BEAM (the Erlang VM), he has decided to make all objects as actors.

The way I look at it, this is mostly a decision of the philosophy of the language design. Scala is targetted to be a general purpose programming language, where concurrency and distribution are not the central concerns to address as part of the core language design. The entire actor model has hence been implemented as a library that integrates seamlessly with the rest of Scala's core object/functional engineering. This is a design decision which the language designers did take upfront - hence objects in Scala, by default, bind to local invocation semantics, that enable it to take advantage of all the optimizations and efficiencies of being collocated in the same process.

The actor model was designed primarily to address the concerns of distributed programming. As Jonas Boner recently said on Twitter - "The main benefit of the Actor model is not simpler concurrency but fault-tolerance and reliability". And for fault tolerance you need to have at least two machines running your programs. We all know the awesome capabilities of fault tolerance that the Erlang actor model offers through supervisors, linked actors and transparent restarts. Hence languages like Erlang, which address the concerns of concurrency and distribution as part of the core, have decided to implement actors as their basic building block of abstractions. This was done with the vision that the Erlang programming style will be based on simple primitives of process spawning and message passing, both of which implemented as low overhead primitives in the virtual machine. The philosophy of Scala is, however, a bit different. Though still it is not that difficult to implement the Active Object pattern on top of the Scala actors platform.

Erlang allows you to write programs that will run without any change in a regular non-distributed Erlang session, on two different Erlang nodes running on the same computer and as well on Erlang nodes running on two physically separated computers either in the same LAN or over the internet. It can do this, because the language designers decided to map the concurrency model naturally to distributed deployments extending the actor model beyond VM boundaries.

Another language Clojure, which also has strong concurrency support decided to go the Scala way addressing distribution concerns. Distribution is not something that Rich Hickey decided to hardwire into the core of the language. Here is what he says about it ..

"In Erlang the concurrency model is (always) a distributed one and in Clojure it is not. I have some reservations about unifying the distributed and non-distributed models [..], and have decided not to do so in Clojure, but I think Erlang, in doing so, does the right thing in forcing programmers to work as if the processes are distributed even when they are not, in order to allow the possibility of transparent distribution later, e.g. in the failure modes, the messaging system etc. However, issues related to latency, bandwidth, timeouts, chattiness, and costs of certain data structures etc remain."

And finally, on the JVM, there are a host of options that enable distribution of your programs, which is yet another reason not to go for language specific solutions. If you are implementing your language on top of the Erlang VM, it's all but natural to leverage the awesome power of cross virtual machine distribution capabilities that it offers. While for JVM, distribution can better be left to specialized frameworks.

3 comments:

Brian Burg said...

It seems, then, that we have nearly come full circle in the debate concerning Actors vs. Objects.

Back in the 70's, Hewitt's seminal papers on the Actor model were influential in the development of Scheme; the relation between continuation calls and Actors is discussed thoroughly in Sussman/Steele's Lambda The Ultimate series of papers.

This time around though, the Actor model is more literally applied, not just to abstractions, but to physically distributed abstractions.

There is also a striking similarity between the unification of actors/objects and process calculi, such as the pi calculus which (oddly enough) also use processes and messages as the model of computation. Much like process calculi, I doubt such a unified model will bring many extra benefits over a Scala-style actors library, while missing out on the well-understood and powerful abstractions afforded by FP and/or OOP.

Jörg W Mittag said...

@Brian Burg re: coming full circle: actually, the circle is even "fuller" than you realize. It dates back even further than Actors, since Carl Hewitt's paper was actually heavily inspired by Smalltalk-71. Originally, Actors and Objects were one and the same, so much so, that there weren't even two different words to describe them – they were just called objects.

This isn't really too surprising, considering that object-oriented programming was invented by two real-world simulation guys (Ole-Johan Dahl and Kristen Nygaard) and a microbiologist (Alan Kay). Both real world objects and biological cells are actors, so it seemed completely natural to these guys to model programming with a network of independent, concurrent entities that communicate with each other via message passing.

This was so obvious to them that they didn't even realize that they had invented a new concurrency paradigm, until Alan Kay gave Carl Hewitt a demonstration of Smalltalk-71, and Hewitt realized that the message-directed execution model of Smalltalk-71 (inspired by PLANNER's pattern-directed execution) could be extracted into it's own paradigm.

Unfortunately, then, Alan Kay made what he would later call one of the biggest mistakes in his lifetime: some of his compiler-savvy colleagues convinced him that he would never be able to implement this efficiently, and in what is probably one of the most tragic instances of premature optimization gone horribly wrong, Kay made two design changes to Smalltalk: he replaced the message-passing execution model with conventional subroutine calls and he introduced the idea of classes.

From then on, Actors and Objects went their separate ways …

iemejia said...

I don't know if i'm wrong, but ASP-calculus based on Active Objects (implemented in Proactive) seems like a marriage of both worlds to me. But It's not strictly clear to me what's the advantage of this one over the others, well apart of confluence.