Our reading group on Bainbridge Island has been working its way through Programming Erlang. Actually we’re technically not done yet, but since I spent a fair amount of time on the ferry recently, I went ahead and finished it off. There’s been quite a bit of writing about Erlang recently, and I wanted to at least have finished the book before jumping in. Looking at Joe Armstrong’s PhD thesis is probably soonish on my list too.
Basics
Erlang is a functional language which incorporates a concurrency model based on very lightweight processes communicating via messages. I’ll cover the concurrency model a bit more below. Since many people have not really been exposed to functional programming, there are things in Erlang which seem odd when compared to more mainstream languages. In addition, Erlang relies heavily on pattern matching as a flow of control construct, and it takes some time to get used to it. Some people liken the pattern matching aspects of Erlang to Prolog, but this is not entirely accurate because Prolog uses unification, which works in “both directions” and not pattern matching, which only works in “one direction”. I can’t say that I care for the syntax of Erlang, but after using Python, there are very few syntaxes that I really like. Erlang supports higher order functions, so closure based control flow structures are included. There is a fairly usual set of basic data types which are provided. Probably the biggest problem with the basics of Erlang is the way that strings are handled. In reality there are no strings in Erlang, and strings are just lists of integers. More on that below.
Concurrency
Much of the current interest in Erlang is due to its concurrent programming capabilities. The foundations of these capabilities are the availability of processes at the language level. Erlang allows a programmer to create and destroy processes quickly and cheaply (in terms of resources). Processes can only communicate with each other by sending each other unidirectional messages. Every process has a mailbox, which is where messages for it are delivered. The messages are queued there until the process explicitly “receives” them.
The code that implements a process typically consists of a tail recursive loop which explicitly “receives” messages and uses pattern matching to examine the messages and dispatch to the correct behavior. Replying to the sender of a message must be handled by the programmer, but it is easy to code up simple rpc style message passing. Two (or more) processes can be linked to each other so that when one process dies, the other is sent a signal. The preferred mode of handling errors in processes is to kill them and restart them. This signaling forms the basis of the supervision tree concept in OTP. The basic concurrency model of Erlang is a version of the Actor model developed by Carl Hewitt at MIT. I took Hewitt’s class while I was an undergraduate, so the concepts were familiar to me. Erlang is relatively blind to where a process might be running – in the same VM, in a different hardware thread on the same VM, or on a VM on different computer altogether. This makes it easy to write programs that can grow easily when you want to add hardware, whether that is processors or computers.
OTP/Mnesia/ETS/DETS
The folks at Ericsson have also provided a bunch of libraries to raise the level of abstraction for concurrent programming in Erlang. There are 3 major libraries. OTP (Open Telecom Platform) helps a programmer to write scalable, fault-tolerant code. It takes advantage of Erlang’s hot code update facilities to allow processes to be upgraded in place. The basic abstractions to do this are very simple to work with. OTP includes the notion of supervision trees, which is an abstraction for managing networks of processes.
Mnesia is a (potentially) distributed database written in Erlang. It provides an easy mechanism for storing Erlang terms. While it is not an RDBMS, it does provide a query mechanism based on list comprehensions. It also supports transactional behavior and has the ability to duplicate Erlang tables on other machines
Runtime
One thing that isn’t discussed enough are the features of the Erlang runtime/VM. The runtime is very efficient at managing processes, much more so that languages like Python, Ruby, or Java. Erlang programs have been deployed in telephone switching products for years, with extremely long uptimes – due in part to Erlang’s hot code swapping capabilities. Java’s hot code replacement or Python’s reload are substantially weaker than Erlang’s hot code swapping. So while libraries that provide an actor like model can help people learn a good programming model for concurrency, it’s less clear to me that the languages (and the implementations of those languages) hosting the libraries will be as good as Erlang when it comes to highly concurrent applications. Of course, if an application isn’t that concurrent it might not matter.
Conclusion
Semantically, there is a lot to like about Erlang – the actor based concurrency model, hot code swapping, higher order functions, and (once one gets used to it) pattern matching. The OTP libraries have been refined by many years of production usage in demanding, commercial applications.
At the same time, there are number of issues which I think are real barriers to Erlang adoption. The syntax will prove difficult for many people, which is a big issue. I’ve already mentioned the problems with string handling, and really that generalizes to a lack of libraries for performing 21st century / web computing tasks. The nice thing about telephone switches is that you don’t really have to talk to the world. But if Erlang is to be viable as a solution for mainstream programming as it moves to more concurrency, Erlang programs must be able talk to the environments around them.
I am aware of several projects where Erlang is being used to do the heavy server lifting and then data is being passed off to programs written in more familiar languages like Python, Ruby, or Java. Certainly this is one way that people could begin to exploit the benefits of Erlang without converting wholesale. It would also give the Erlang community some time to improve Erlang to the point where it could be adopted by a larger audience.
I still haven’t finished the book yet, but one area where it really shows its heritage is its handling of bit-level constructs.
Some of the example code, walking through binary file formats and munging protocol headers is very simple and powerful.
I haven’t really found a good use for the language in my day-to-day work, but if I wanted to analyze network protocol headers, it would be a good choice!
(I wonder if one could think of strings in a similar way, providing language constructs that worked at the character and string level instead of bits/bytes? )
As far as overall language adoption, its not just the syntax but also the semantics. A lot of people don’t “get” pattern-matching and recursive functional style.
It seems like people with Lisp/Scheme/Prolog familiarity pick up on it again quickly (since they do the same thing) but people used only to procedural/OO semantics
have a little more trouble grasping it at first.
Once they do, then its a matter of deciding upon the utility of it!
I think that the important applications are yet to come – I’m not sure that it will be that worth it to rewrite existing applications in Erlang unless that application is having perf/scalablity problems.
I’m really enjoying the book so far. This is the first functional language that I feel like I’ve really understood (maybe that’s just because the book is written so well).
I’m also going to have a hard time finding immediate use for it though. I’m curious as to how Erlang pros do it. Do they use Erlang as their default choice, and move to another language only on rare occasions?
I’m a Python guy, and Python fits so nicely with everything I do, it’ll be hard to find places for Erlang to fit. I’ll certainly try though!
Ted, you mentioned that you knew of some Python/Ruby/Java apps that were mixed with Erlang. Could you mention some? I know that Bob Ippolito does that with MochiAds, but it’s all I’ve heard of. Something open source would be very interesting to see.
Ted – good summary.
Jay – check out From Python to Ruby on Rails to Erlang
http://slideaware.typepad.com/slideaware/2007/04/from_python_to_.html
Yep, agreed on all counts. 🙂
Actually, Erlang lands somewhere in the middle between Prolog’s unification and pattern matching found in a language like Haskell or (S|OCa)ML. It’s true the variable bindings only go one way (so the variables aren’t Prolog’s Logic Variables), but you can do things like
> {A, A, B} = {abc, abc, foo} %% A binds to abc, B binds to foo
(the above completely and gratuitously copied from http://www.erlang.org/course/sequential_programming.html#patterns)
which you aren’t allowed to do in Haskell or the MLs.