Why Elixir is More Than Just Syntax Sugar Over Erlang

4 minute read

In my first year of using Elixir, I fell deeply in love with the language. However, I never really thought about why I liked Elixir so much. I mean, I can list many reasons, such as the Pipe Operator, Pattern Matching, and the powerful and flexible GenServer.

So, if you asked me, I would definitely say it’s the syntax. Coincidentally, I soon encountered a colleague. I was eager to recommend Elixir to him, but he said, "Elixir is just syntax sugar over Erlang, right? So why not just use Erlang?"

This left me speechless because, yes, Elixir is indeed "just" syntax sugar.

What is Syntax Sugar

Simply put, syntax sugar is something that makes your code easier to read, understand, and write. Honestly, I don't really like the term because sugar gives the impression of being superficial: "This thing doesn't help with performance; it only makes it easier to learn and understand, which only beginners need!"

At least, that’s how I felt when I first heard the term.

PS: It's said there's also something called "syntactic salt," which uses human-unfriendly syntax to make writing code more painful. It can also prevent coding errors, but it likely decreases programming efficiency by raising the syntax learning curve, making people salty with frustration…

Code is for Humans

First, we should not underestimate the importance of syntax sugar. Code is written for humans, not machines. Easily understandable code means easier maintenance, more straightforward iteration of new features, easier test writing, clearer logic, and greater reliability.

Syntax sugar facilitates these goals, making it easier for the entire development team to practice them. You might think you don't need it, but development work often involves a whole team. In this context, the advantages provided by good syntax sugar are not negligible.

The Biggest Challenge in Software Engineering

I once saw a quote on RubyChina that left a lasting impression: "I believe the biggest challenge in software engineering is continuously meeting business complexity while maintaining the maintainability of the project."

Yes, I completely agree, and the role of the language in this aspect is crucial. Additionally, functional languages are truly user-friendly. Many open-source libraries in OOP languages, especially the more complex and poorly written ones, leave you clueless when reading the source code on GitHub.

You can’t clearly see the runtime state just by looking at the code. You need to clone it, run it, and debug it to see the value of certain variables at specific times and states. Compared to procedural languages, functional languages eliminate the concept of time. When I open Elixir's source code, it's easy to understand because there are no tangled dependencies.

Everything has input and output. As long as you can imagine the input data, you can predict the output. This makes writing tests much easier, a significant advantage in maintaining project maintainability.

Let It Crash

At first, I didn’t understand the "let it crash" design philosophy. I wondered if writing more maintainable code but causing every exception to crash was appropriate.

Many languages treat exceptions as a form of control flow. In some cases, only the ideal flow is described with if/else/case, and all other situations are designed as exceptions. Elixir does not use exceptions as a form of control flow. Exceptions are only used for things that are "almost impossible to happen under normal circumstances," such as database disconnections, HTTP request timeouts, and missing configuration files.

Anticipated situations are generally handled with `{:error, reason}` and pattern matching. However, as I learned more, I found it very reasonable. No program can handle all unexpected situations. In such cases, a simple restart to ensure the service doesn't go down is a better approach. For example, if your computer crashes due to a power outage, you just restart it without further investigation because it doesn’t make sense to do so.

Conclusion

Elixir is not just a faster horse. As Henry Ford said, if he had asked people what they wanted, they would have said a faster horse, not a car. In my years of working with Elixir, I can’t say Elixir is a car, but it’s definitely not just a horse.

Elixir/Phoenix has changed many of my views on software development. For example, a basic web application involves some text coming in and some text going out. Why should we generate hundreds of objects in the process instead of thinking of it as a data stream passing through a server production line, transforming into the required format?

Ecto’s approach to validation for saving to the database is similar. ActiveRecord involves an object that must meet certain conditions to be saved. Ecto, however, is a data processing pipeline. Data must pass through the pipeline to reach the database, with inspectors ensuring quality at each step. If any inspection fails, the data isn’t saved.

The same type of data can pass through different pipelines based on different conditions. For example, user login and user registration can have different pipelines. Implementing conditional validation in some imperative languages is quite painful.

Therefore, the maintenance ease and clarity brought by Elixir’s syntax sugar become more apparent in larger projects, especially those with complex data flows. Yes, Elixir is just syntax sugar, but it’s more than just syntax sugar.