Foreign Language Lessons, part 2

Posted in programming -

So, last time when I was talking about Lisp, I said that even if I didn’t end up using it, I hoped I might learn things from it that I could apply to other languages. I kinda had one in mind when I said it, and that one was Erlang.

What?

Erlang was developed back in the 80s for programming telephone switching equipment. That sounds pretty bizarrely specialized, right? The problem they had was pretty much unique back then. They had all these machines that had to talk to each other. The individual messages, the requests they had to process, were relatively simple, but the system as a whole had to deal with an absolutely ludicrous volume of them and be perfectly reliable. You probably make hundreds, if not thousands, of phone calls a year. If even two or three of them got dropped, you’d say your phone system is pretty crappy. “It keeps dropping calls.” And if the whole system went down for like an hour, they’d never hear the end of it.

These days, a lot of people have this problem. Not just phone companies, but pretty much anyone who runs a popular web site or instant messaging service. A lot of enterprise software now relies on a “message bus” to handle communications between various chunks of code on different servers. Anything having to do with credit card processing or financial markets also needs that cocktail of high volume and high availability.

So what’s so special about Erlang?

Erlang was built from the ground up with this sort of thing in mind, not just as a concern but as its raison d’etre. There are really basic things that Erlang doesn’t let you do because they cause problems at scale in a massively multi-processing environment. Like, it doesn’t let you modify data structures. Once you’ve created them, you can copy them over and change them on the way, but you can’t change the original. Why? Because that forces you to communicate the change explicitly, and nobody has to worry about data getting yanked out from under them.

That’s the programming equivalent of rugby players taping their ears to their heads. The fact that people feel the need to do that tells you something about the seriousness of the situation.

On the other hand, Erlang has features that make it easier to write these sorts of massively concurrent and robust programs. Spinning off a new process is trivial, a single command, as is sending messages to it and even registering it as a service so that other processes can talk to it. Doing that on a remote machine isn’t much more than adding its name or IP to the command. I’ve done that sort of thing in Java, but holy crap it’s a lot of hassle.

The fact that this is a simple and routine part of Erlang programming also tells you something about the nature of the situation.

The crazy thing that Erlang lets you do (again, easily) that I haven’t seen in any other language is that it lets you update code while it’s running. This is not to be confused with the half-assed thing Java application servers do: If they’re running in “development mode” (so not recommended for production use), they can recompile updated JSPs; or they can shut down your whole app and restart it, leaking memory like a sieve the whole while. In Erlang, all these separate processes can individually reload their code whenever it suits them. You don’t have to shut down the server. You don’t have to coordinate all the processes in some way. You just set it up so that the next time a process does its thing, it does it with the new version of the code. Here’s what it looks like:

-module(countdown).
-export([init/0, reload/0]).
-export([tick/1]).  % so we can spawn this properly.

%% spawn a countdown process with a default start time of 10 seconds.
init() -> init(10).
init(Time) ->
    register(ticker, spawn(?MODULE, tick, [Time])).

tick(Time) when Time >= 0 ->
    io:format("Tick ~p~n", [Time]),
    timer:sleep(999),
    receive reload ->
        ?MODULE:tick(Time - 1)
    after 1 -> tick(Time - 1)
    end;
tick(_StartTime) ->
    io:format("Boom.~n", []),
    done.

reload() ->
    ticker ! reload.

(Calling “?MODULE:tick()” causes the code to reload; plain “tick()” doesn’t. Full example with alternate version and commentary.

The syntax probably looks kinda foreign, but simple enough that you can puzzle it out. It just creates a countdown timer called “ticker”, but it comes with a reload command that tells it to update itself. In the middle of counting down, you could swap in a new version that prints something different, or counts slower, or starts counting up. It’s a trivial example, but that’s the point: it’s trivial. Doing this in any other language would be somewhere between mind-bendingly complicated and flat-out impossible. It certainly wouldn’t be something you’d do to make your program more reliable. But Erlang has this whole infrastructure for not only updating your application while it’s running, but rolling back to the old version if you find you’ve screwed something up.

So Erlang is technologically cool, and useful in an increasingly broad range of applications. But part of the appeal for me is also that it’s kinda weird. As with Lisp, the programming toolkit is not like most other languages, and it forces me to think about problems in a very different way. That makes it more interesting as a hobby, and it may also make it more valuable as a professional skill. There’s a lot of demand for Java, but there’s also a lot of competition. Erlang is more of a gamble. It may not catch on, but if it does, all that weirdness is going to thin the competition.

Until then, it also means that the Erlang community is mostly made up of people who actually love programming. They’re not just trying to get a job. They’re smart and passionate about what they do. They’re fun to hang out with and they seem to like beer. So worst case, I’ll have fun learning it.

(Most of Paul Graham’s older essays about why you should use Lisp also apply to Erlang.)