Pony is a relatively new actor based programming language. It’s inspired by Erlang, but differs in some important (and cool) ways. I wanted to learn about Pony’s message passing model, so I decided to write up a solution to the dining philosophers problem. Here’s what I found. The code is available on github if you’re interested in that.
The Pony Language
Type systems are cool. Type systems are one of those things I appreciate more and more as I get older: good cheese, the piano concertos of Mozart, a nice type system. You know, the usual. Pony is an actor based language inspired by Erlang, but with static typing. In fact, the type system is one of the most interesting and new ideas of the language from my perspective. I think that Pony provides a great example of the “lightweight formal methods” Benjamin Pierce refers to in TaPL: the type system is used to show that certain invariants hold, and these invariants are used to make certain operations safe. Interestingly, the invariants also allow optimizations that make message passing into a viable model for high performance applications.
As a short explanation of this, consider a set of actors, lightweight processes all running at the same time, that need to share data. Copying the data is expensive, so we don’t want to do that. If more than one actor has access to an object, it’s easy to write incorrect code: data races, deadlock, livelock, every other horrible thing that comes when programming with shared memory. We’d like to avoid that if possible. That’s where Erlang comes in, because Erlang made message passing only, no shared state style programming mainstream. This type of code is highly scalable, automatically avoids many mistakes commonly made in the shared memory setting, and often provides a clear metaphor for programmers to think about a concurrent system.
Type systems and performance
Erlang style message passing has its drawbacks, though, and a big one is performance. Since nothing is shared, there’s a lot of copying. This includes the “messages” that make up the communication between processes themselves. When processes are running on remote machines, this is obviously unavoidable. But on a modern computer with lots of cores, the copying (and the allocation and everything else that comes with it) takes a lot of time compared to programs written in a shared memory/locking paradigm, and this has turned off some performance oriented folks in the past.
So how could we allow actors to communicate and share things without worrying about copying? One way would be to share immutable objects. Since the objects don’t change, there’s no way introduce a data race. Immutability is a strong condition, though, and I think it’s fair to say that lots of programmers would consider it quite restrictive. Another way to prevent problems caused by concurrent access to an object is to ensure that only one actor has a handle to the object. That way, the actor can change the object however it likes, and later pass it on to another actor. When it does this, it gives up its access to the object. Another way to say this is that aliases to the object are not allowed.
The Pony type system allows programmers to express these ideas and more right in the language. (In fact, this is related to ownership and moving issues that I’ve been interested in lately, although not so much to lifetimes since Pony is garbage collected.) As a consequence of the invariants that can be shown using the type system, objects and message do not need to be copied. This results in a potentially large performance boost for Pony style message passing. I’ll let you read more about exactly how this works, but it’s very interesting, I’ve never seen these ideas quite like this, and I dig it.
I’ve talked about the dining philosophers problem before, but this solution requires a bit more creativity. The issue is that Pony includes no locks. This makes sense if you think about it, because what would there be to lock? There’s no shared state! Furthermore, Pony includes no blocking operations at at all. Yeah, that’s right. You can write a big loop, but your loop can’t exit conditionally on the behavior of some other actor. That’s what makes Pony’s concurrency model so powerful, able to avoid deadlocks and so forth entirely. But it also makes programming a bit more… challenging.
In the early 80’s, K. M. Chandy and J. Misra gave a beautiful solution to a distributed version of the dining philosophers problem in their paper The Drinking Philosophers Problem In this version, the philosophers are hanging out on several machines and can only communicate by message passing. I highly recommend the paper, as it is quite readable but very deep. I implemented this solution in Pony as an exercise; you can see my Pony implementation on github. I make no claims about my implementation; it seems to work great but I have not checked closely that the algorithm I’ve implemented is identical to Chandy and Misra’s.
One notable thing about the code is that it does not use Pony’s alias syntax (because it doesn’t need to). This is perhaps a sign that Pony defaults to doing the right thing, and that a more complicated type system doesn’t necessarly get in the way of writing code. In fact, I think the code is pretty clear if you consider the fact that the author is not fluent in Pony and doesn’t write terribly idiomatic code.
My experience with Pony wasn’t without trouble: The version of the Pony compiler I used generated fast code, but the memory usage was high even though I was careful to ensure that messages didn’t pile up in actors’ mailboxes and that actors had ample time to GC between methods. Documentation is good but not great. The community is very helpful, but small. Pony requires us to change the way we think about programming, and this is always difficult.
Having said all of that, I think Pony is a very cool language. You have to fight a bit with the compiler, learn some new ideas, and change your way of thinking. In return you get strong guarantees about program behavior, potentially highly scalable systems, all in a language that feels more like a scripting language than a high performance language for programming lots and lots of cores.
But note that Pony is not somebody’s weekend project. It’s got some publications behind it, including a formal description of the typing relation and an operational semantics. I don’t know about you, but it says good things to me when language designers bother to give their language an operational semantics. And Pony isn’t just an academic experiment, either. Code is being written in Pony; you can read more on the website.
I would say that Pony has the potential to combine the good parts of Erlang with the performance of something approaching C/C++. I really dig Pony and am going to try to learn more as I have time. I encourage you to check it out, too!
Approx. 1188 words, plus code