Part 1: ErlangVM vs V8 vs Java VM
To me, the biggest reason why Elixir should be the go-to in 2020 is because it is essentially Erlang. That‘s an odd statement, to say the least, and perhaps not entirely true, but Elixir is really just a modern, macro-based dialect of Erlang, which is really what makes it so powerful.
I’ll go a bit more into macros later in this series, but to start I’m going to explain what the Erlang VM (BEAM) is and why it’s far more appropriate for building web servers and APIs than most popular alternatives available today. Secondly, I will compare the Erlang VM and its relationship to Elixir with V8, which is basically the ‘Javascript’ VM, and its relationship to NodeJS. Finally, I’ll touch on the Java runtime, Scala, and how they compare to Elixir and the Erlang VM.
What is a Virtual Machine/Runtime?
If you’re not exactly sure what a VM/Runtime is, the best way to think of it is as an operating system within an operating system. A VM abstracts away the underlying architecture (i.e. Windows, Linux, Mac OS X etc) of a machine so application developers don't have to write buggy platform-specific code. Runtimes often offer a layer of abstraction over the underlying OS and may take care of complex tasks such as memory management (garbage collection) or async workflows & multi-threading.
Not all programming languages have a runtime. A true 'low-level' programming language does not have a runtime, and a great modern example of that is Rust. Most web/api languages, however, do have somewhat of a runtime, even if it's relatively small, as in the case of Go. Other common examples of runtimes are V8 (web-browser runtime) and the JVM (the Java runtime).
ErlangVM/BEAM
To understand the Erlang VM and what makes it desirable, let’s look at the reason it was built. The Swedish Telecomm company Ericcson built Erlang in the late 80’s for a specific purpose — to build highly scalable, fault-tolerant, distributed applications).
Erlang introduced an innovative and scalable model for asynchronous programming called the Actor Model. No, this is not your typical L.A. resident, it is a way of handling massive concurrency by using lightweight processes called 'green threads' that are much smaller and more efficient than typical OS threads and can be scaled to hundreds of thousands and potentially even millions on a single machine.
There is plenty of material out there regarding this paradigm, and I don't want to get into too much detail here, but suffice it to say it is one of the more powerful solutions to dealing with concurrency and really is the 'secret sauce' of Erlang/Elixir.
OOP
Despite many redeeming qualities, Erlang did not catch on, at least in a mainstream fashion, likely due to the emergence of object-oriented programming that challenged the functional programming paradigm of the day. It was, and still is, very popular for telecomm company, but is not used extensively in other areas. Fast-forward to 2020 and now functional programming is re-emerging, especially in the front-end world, and handling massive concurrency is one of the biggest challenges web/api developers face today. Meanwhile, nothing has even come close to addressing all of these same concerns ‘out-of-the-box’ like Erlang has. A few key features that the Erlang VM offers right out the gate are:
- A top-tier concurrency pattern based on the actor model; lightweight threads/green-processes somewhat analogous to Goroutines in Go or Tokio in Rust.
- Well-established applications and patterns available via Erlang OTP (GenServer, Observer, Dialyzer etc)
- Functional and immutable by default
- A revolutionary method of error handling
- Networked applications without K8s etc.
- Hot-code swapping; more sophisticated than anything available today. Arguably engineers aren’t quite ready for this even though the tech has been available for decades with Erlang.
To get some of these in a language is a plus. To get all of these is unprecedented. What’s more impressive is this was all done 30+ years ago, making Erlang perhaps the most mature language out of Node, Go, Rust, Ruby, PHP, Javascript, C
, Python and even Java (built 10 years later).
The industry move away from functional programming towards object-oriented programming is likely the biggest reason Erlang isn’t as popular today as it should be. With a modern resurgence of functional programming, paired with the growing needs of todays application, Erlang, via Elixir, is making a comeback, and I’m betting it’s going to be a big one.
The WhatsApp Case Study
The best possible example of the power of Erlang is the WhatsApp case study. If you are unfamiliar, Facebook bought WhatsApp, and its 400 million users, for a mere $18B. A huge part of their tremendous success, however, is attributed to the use of Erlang, enabling WhatsApp to scale easily and catch the eye of Facebook from an engineering perspective as well. A few highlights from the case study are:
- 450m users handled by an engineering team of 35 when acquired
- As of 2015, 900m users with 50 engineers
- Ran up to 2m concurrent connections on a single machine
WhatsApp goes to show how efficient Erlang can be, especially in highly-concurrent systems that mimic modern telecomm, which is a large portion of existing APIs and web servers that exist today.
V8
As we now know, despite being over 30 years old, Erlang solved most of the issues even modern languages today struggle with, and was designed specifically for that purpose. V8, however, was designed for an entirely different reason: to run Javascript in a web browser.
Think about that for a moment. Instead of building services on a mature VM designed over 30 years ago for highly concurrent, fault-tolerant, distributed systems and micro-service architectures, we are building them on a VM optimized for the web browser. And then using Javascript. And not even standard Javascript, but a hacked-together Javascript that requires a ‘compiler’ (Babel, Webpack, Typescript etc) but is still interpreted.
10 years ago the whole “single-threaded non-blocking async IO” pitch was a competitive option, but in 2020 you can do far better in terms of asynchronous processing, and with a far less clunky language.
I’m not even going to go into specifics of the event loop and how V8 compares to BEAM. All you should need to consider is the purpose of the runtime; one is built to run the world’s telecomm, the other a web browser. I think it’s amazing Node works as well as it does considering how crazy that sounds when you think about it...
Java VM
I haven’t really worked much with Java in my career, and would consider myself novice at best. I think we’re all familiar with the Java runtime, the JVM, however. It is a fairer comparison to BEAM because it was actually built for the reason it is being used, mostly to build enterprise applications and web servers.
I am no expert on the Java VM, but I know it is known for being bloated and can be slow, but does have all the low-level features you’d need for async work and system-level tasks/multi-threading.
What I find interesting about the Java VM is Scala. Java is perhaps the least functional language available. It is built on object-oriented programming and classical inheritance, and naturally the runtime has evolved accordingly. Meanwhile, due to the merits of functional programming and overall trend towards FP, especially on the front-end, Scala has been ‘layered’ on top of Java, offering a functional ‘flavor’ or dialect to the language.
To me, it is counter-intuitive to try to make Java something it is not. Even if the language is useable or even pleasant to work with, there has to be somewhat of a dissonance with the underlying VM that was built and optimized around a complete opposite paradigm.
Rather than go into technical details in this article, especially in areas I’m less qualified to comment on, I thought it should be more of a ‘gut-check’, a simple assessment of top competitors to BEAM and what purpose they were designed for:
BEAM — Built by a Telecomm company to create highly-scalable, fault-tolerant, distributed systems that can be updated live
V8 — A Javascript interpreter that was built and optimized primarily for web browsers and later adapted for server use via NodeJS
Java — An effective general purpose/enterprise runtime optimized around object-oriented and classical inheritance programming, the opposite paradigm of Erlang, which is functional and dynamic. Scala, however is functional and typed.