Programming language review: Erlang
Jul. 13th, 2017 08:27 am![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
What do you get if you combine Haskell's basic functional style, Lisp's type system and object representation, a unique concurrency system, and a very good runtime?
In my current free time, I decided to play around with Erlang, which has a reputation for robustness. Only a couple of "real" things (most prominently RabbitMQ) are written in it, but they have a reputation for being rock-solid and for scaling well. (Also I'm looking for the HTTP/REST library of my dreams; more separately.)
Some quick running through tutorials found a lot of familiar parts. The standard library includes standard containers and robust operations on them. It's very common to pass around tuples with atoms as their first element, or lists of them; Lisp '((a . b) (c . d)) would nearly directly translate to Erlang [{a, b}, {c, d}]. This unsurprisingly makes static analysis hard, and the provided type-checker (dialyzer) is slow, assumes code is correct if it can't reach a conclusion, and in practice couldn't catch errors where a property list was missing a required key.
Trying to build a real application, similarly, ran into many familiar problems. There are two competing third-party build systems, Rebar and erlang.mk. There is a central package repository, hex.pm, but cross-version compatibility is still an issue, semantic versioning gets a wink and a nod, and many packages are, well, GitHub quality. The documentation on how to set up and run a complete application is extremely buried, and you wind up with a magic control file that has a mix of low-level tuning parameters and required code references.
The runtime, from the looks of things, is pretty good, but if you jump straight to high-level libraries you don't see much of it. The Web service I was trying to write had no occasion to spawn() a new subprocess or directly send or receive messages, and beyond some supervisor boilerplate didn't pay much attention to process lifetime. If you're working that high in the stack, it probably doesn't matter much whether you have a good language runtime that can recover gracefully from errors or if it gets pushed up into libraries, just so long as it works.
Style-wise, then, a packaged "release" with multiple "applications" in it feels like a bundled Java app server, more than a collection of microservices. If I was building a real, large Erlang application, I'd try to have everything but the UI in Erlang and rely on Erlang's native clustering, over newer tricks like Docker and Kubernetes.
In short, Erlang looks like a good language, a little dated, but I'd rather have good static checking and a robust library stack than an excellent runtime with okay libraries, especially if I can avoid peeking "under the hood".
In my current free time, I decided to play around with Erlang, which has a reputation for robustness. Only a couple of "real" things (most prominently RabbitMQ) are written in it, but they have a reputation for being rock-solid and for scaling well. (Also I'm looking for the HTTP/REST library of my dreams; more separately.)
Some quick running through tutorials found a lot of familiar parts. The standard library includes standard containers and robust operations on them. It's very common to pass around tuples with atoms as their first element, or lists of them; Lisp '((a . b) (c . d)) would nearly directly translate to Erlang [{a, b}, {c, d}]. This unsurprisingly makes static analysis hard, and the provided type-checker (dialyzer) is slow, assumes code is correct if it can't reach a conclusion, and in practice couldn't catch errors where a property list was missing a required key.
Trying to build a real application, similarly, ran into many familiar problems. There are two competing third-party build systems, Rebar and erlang.mk. There is a central package repository, hex.pm, but cross-version compatibility is still an issue, semantic versioning gets a wink and a nod, and many packages are, well, GitHub quality. The documentation on how to set up and run a complete application is extremely buried, and you wind up with a magic control file that has a mix of low-level tuning parameters and required code references.
The runtime, from the looks of things, is pretty good, but if you jump straight to high-level libraries you don't see much of it. The Web service I was trying to write had no occasion to spawn() a new subprocess or directly send or receive messages, and beyond some supervisor boilerplate didn't pay much attention to process lifetime. If you're working that high in the stack, it probably doesn't matter much whether you have a good language runtime that can recover gracefully from errors or if it gets pushed up into libraries, just so long as it works.
Style-wise, then, a packaged "release" with multiple "applications" in it feels like a bundled Java app server, more than a collection of microservices. If I was building a real, large Erlang application, I'd try to have everything but the UI in Erlang and rely on Erlang's native clustering, over newer tricks like Docker and Kubernetes.
In short, Erlang looks like a good language, a little dated, but I'd rather have good static checking and a robust library stack than an excellent runtime with okay libraries, especially if I can avoid peeking "under the hood".