In recent years, many language ecosystems have developed automatic code formatters to reduce the mental overhead of code readers and therefore to share code more easily. These tools work by ensuring that all code written in the same language looks the same. Some examples of these tools include gofmt for Go or mix format for […]
In recent years, many language ecosystems have developed automatic code formatters to reduce the mental overhead of code readers and therefore to share code more easily. These tools work by ensuring that all code written in the same language looks the same. Some examples of these tools include gofmt for Go or mix format for Elixir. The Erlang community was lacking a tool like this, so we created a rebar3 plugin just to automatically format code.
In this article we’ll discuss the history of the Erlang parsing and formatting tools, the challenges of developing a formatter and the resulting tool that we created. Learn how you can use it and customize it to your needs.
10-15 minute read
Bugs Bunny – The Rabbit of Seville.
NextRoll’s RTB Team devotes quite a bit of our efforts to make our codebase as mature and maintainable as we can.
For our Erlang code, we started working on this task years ago. We trim dead code using
xref. We remove discrepancies with the help of
dialyzer. We make sure our code is well behaved using
PEST. We let Elvis find stylistic anomalies…
But there was one tool that was missing: a code-formatter. We were using a code formatter for Go, Elixir, and Python. But there weren’t any (or barely any) for Erlang. So, we decided to use one of our HackWeeks to create one.
Code formatting is certainly nothing new, it’s been around for ages with several very interesting papers written about it. But recently, there’s been a tendency in all modern languages to include one (and only one) formatter, like
gofmt and, of course, the one that influenced us the most:
We’re by no means experts in this area and therefore we wanted to rely on existing efforts as much as we could. We took inspiration from all of them, but we tried to use as many already written components as possible, and (as usual) there are a bunch of them already baked into OTP…
Our first initiative was to try to find existing tools to format Erlang code.
We found a ready-to-use solution:
rebar3 fmt. The problem is that, as it clearly states in its description, it requires emacs, which is something most of us don’t use. But it pointed us to what is generally recognized as the de facto standard for Erlang formatters: erlang-mode for Emacs. That’s what the OTP Team considers the standard way of formatting Erlang code and what the other tools included in OTP are loosely based on.
What are these tools you say? That was our follow up question as well! And these are the ones we found:
erl_tidy: The closest thing to an automatic code formatter for Erlang. It uses many of the other modules in this list to parse and rewrite Erlang code. It’s a bit old and it has a bunch of well-known deficiencies, including but not limited to its lack of proper support for macros and comments in code.
erl_prettypr: This is a pretty printer – it takes an AST (Abstract Syntax Tree) as an input and it prints it out in a pretty way. It’s the standard Erlang pretty printer. Our original intention was to use it, but its extensibility support is complex and poorly documented at best. So, like many others before us (e.g.
erlang-ls, etc.), we just copied it into our project and started from there.
epp: The other side of the story. This is the Erlang parser that comes with OTP. It also has some limitations, most importantly when it comes to macros and comments, since it’s intended to be used primarily by the compiler.
epp_dodger: A module explicitly created to work like
eppbut bypassing macros and preprocessor directives. It’s also a bit buggy and it has limited support for extensibility. Luckily, Juan Facorro already copied it and improved it in
So, what we ended up using is
katana-code) to parse the code and turn it into an AST and then our version(s) of
erl_prettypr (more on this below) to output the formatted code.
Once we had the tools, we developed our very first version of the formatter (you can still find it on hex.pm as
0.0.1). That version simply passed the provided Erlang code through the tools and generated the code formatted with
For a while, we considered that to be the canonical formatting since, you know, it comes with OTP, right? But we (and many others like us) didn’t want our code formatted strictly as
erl_prettypr outputs it.
So, we started adding configuration options to be able to adjust the formatter to our tastes. After a while, though, we realized that what we wanted was not an extension of
erl_prettypr, it was a different formatter. That’s when we moved from one formatter with lots of options, to a formatting behavior with multiple implementations.
Our favorite way of formatting Erlang code is now encoded in the
default_formatter, but we kept the OTP-approved way alive as the
otp_formatter. And now you can define your own, too.
While doing our research, we found that we’re not the only ones who saw the need for an Erlang formatter. As a matter of fact, several people are working on different code formatting tools for Erlang these days:
rebar3plugin that you can use:
erl_tidyand wrote a PR for that.
steamroller, by Daniel Tipping.
erlfmt are much more opinionated than our formatter, mostly because their authors aim at having consistent formatting across all Erlang codebases in the world, much like the goal of
We see that as a great goal, but we have a fairly smaller one: What we want is consistent formatting within all Erlang codebases in the world. In other words: We want all modules in each project to be consistently formatted, even if they don’t share the same formatting rules with other projects.
After all, at this point it’s hard to even define the canonical formatting for all Erlang code in the wild. And if we achieve our goal and some developers format their code using
rebar3 format and you (another developer) can’t read their code because it is using a different formatter than the one you’re used to (e.g. they use a comma-first ROK-style formatter), all you need to do is switch an option in the
rebar3 format and magically… that ugly code now looks your way.
But enough with the history, let’s see what you can do with this tool.
Just add this to your
rebar.config (either in your project or globally in
If you don’t really like the default formatting as-is,
rebar3 format can be configured using the
format section of the
rebar.config. There are three main options you can specify.
To determine what files the formatter should format, you use the
Unless you specify otherwise,
rebar3 format will always use the default formatter that’s baked into it. But if you want you can use the
otp_formatter or your one, like this:
Finally, you can also set up individual options for the formatter you want to use. For instance, for the
otp_formatter you can change
paper (i.e. the expected max width of the formatted code):
To find out the options for each provider, check out the docs that are available online.
Drawing from the Smalltalk formatter experience that I had (where the code was formatted only when presenting it to the developer but not when stored in the image itself), I want to propose a workflow for teams where each member has its preferred style for code formatting.
The idea is to take advantage of
rebar3 profiles and write the following on your
Then whenever you’re about to work on something, follow this ritual:
Miriam does the same but using
as miriam instead of
That way each one of us can read code in the way we understand it better, write code exactly how we like to write it, etc. Then publish it in a consistent way that matches the style of the rest of the project.
If you want to see what the formatter can do to your code, the best place to go is the sample project on the repo itself. All sorts of examples are there with as many edge cases as we could create and find. If you know of others, please contribute by adding them there or writing issues so we can add them.
As the best code reviewers out there may notice, those PRs required some manual adjustments after processing the code with the formatter. We consider that a feature: That’s the formatter allowing us to spot very ugly pieces of code (e.g., too deeply nested structures) that we should refactor.
To be clear: the formatter didn’t break our code (it has built-in verification for that), it just made it look extremely ugly, therefore prompting us to beautify it.
Bugs Bunny – The Rabbit of Seville.
We’re releasing the formatter as early as we can to catch as many bugs and nuances as possible. Please try it in your code and report any bugs and new ideas you have here.
We plan to keep using this ourselves, but if anybody feels like making this tool official (if you’re a member of the OTP Team, this message is 100% for you 🙄), that would be amazing.
As a bonus track, I wanted to know how does my favorite piece of code look like when formatted by
rebar3 format. Let’s see…
Not bad, huh?
Bugs Bunny – The Rabbit of Seville.