Erlang's biggest gotchas?

When you first started using (or learning) Erlang, what did you find most challenging? Anything? Nothing? Please share - your insight could help others :blush:


I miss mix. In Elixir, after you install it, you can just do “mix new project” and then “mix test”. It is not that easy in Erlang.


Interested in feedback on how we can improve rebar3.

Is the main thing that installing Elixir installs mix? There has long been interest in either moving rebar3 into Erlang/OTP or some other way to have them install together even if they are in separate repos and simply packaged together. Sadly it is a good bit of work.

Or is it something about mix’s new and test that makes them prefered over rebar3 new and ct/eunit.


FWIW, we currently use mix to compile a multi-app (umbrella) Erlang project. We started on rebar2, moved to rebar3, then used for a while, then moved to mix.

Some links:


Well actually this is a big topic I suppose :grinning:. This topic can have several points. I will try to describe as briefly as possible each of them that I experienced as a self-taught who came from the world of OOP.

Functional languages world
First of all a lot of points and knowledge what you can get from OOP world basically is not suite and you need to prepare yourself from the beginning that everything that you knew before you do not need at least the bulk of this knowledge, you need to be mentally prepared for the fact that you will study Erlang literally from scratch. Definitely, with the advent of Elixir, this transition occurs more smoothly and for this the guys from the OOP world Elixir looks more friendly syntax etc.

Missing current forum
You can try to communicate with people on different topics in but you will not replace the forum as the current one. The lack of such a forum is also to some extent an obstacle for beginners, I think.

How to start
A lot of information is provided in internet, topics, videos, books, open source projects etc. On the one hand, this is good now, since you can find almost any answer to your question, but on the other hand, when there is a lot of this information, the beginner begins to get confused and does not know where to start. By this reason for new guys, I have prepared a number of links that may be useful to them:

Build tools

The main issue I supposed is in chosen of tool for build Erlang projects. From one side don’t have a lot of issues when you try use it in any OS and some time ago it was more friendly. On the other side rebar3 has become an incredible machine for which you can write plugins, which has many possibilities, etc. plus it is already quite close to the OTP. But if you choose for build tool what expected for use in rebar3 projects you will also need to arrange dancing with a tambourine around this project in order for it to be rebar3 compatible - which is also not always fun as we would like. I have seen many projects that are built on a rebar and can be used in - but there are quite a few projects that use and can not be integrated into a rebar project without additional effort. In any case, it’s a matter of taste but both these tools do their job very well.

First Erlang job
Of course this is also a big issue when you are in a company that does anything but develop on Erlang. And when you say to yourself - that’s it I want to make the most of Erlang you cannot find a suitable company or due to the fact that rather narrowly focused technologies are used which you did not know exist or they need a specialist of an incredible level for low salary. But it’s very good that there are sites like and where you can find and detect what exactly companies is use Erlang and can hire you.

All of the above refers only to my subjective opinion and previous experience, perhaps some points are debatable, but nevertheless I’m decide to share this, it may be useful to someone of beginners.


From my perspective, I could add that being familiar with concurrency will help a lot in learning OTP.

If you miss such background and its your first exposure to environment where everything is concurrent by default, you might consider investing time in playing with processes on your own, e.g.:

  • create, destroy a bunch of processes
  • organize them in some way
  • enable communication exchange between them
  • write a process that responds to messages in the loop
  • learn how you register and find a process in the environment

Also you might play around and try to visualize the processes execution in some way:

  1. observer might be useful if you like GUIs
  2. add some io:format including self() output
  3. or if you’re ambitious - invest in learning how to enable simple tracing - the earlier you posses this knowledge the better (edbg might be the easiest to learn I’ve seen so far, looks like great tool for learning)

I like rebar3. It is mostly that when you install Elixir it already comes with mix and that “mix test” is easier to remember than “rebar3 eunit”.


One thing I miss in rebar3 moving between Elixir and Erlang projects is the ability to run a single unit test by line number. Like mix test tests/xx/yy.exs:234. This is obviously not supported by eunit itself at this time, but would be super handy if a way could be found, especially in large projects, and when doing TDD.


Ok, gotcha, thanks. Hopefully we’ll get the install issue taken care of in the near future :slight_smile:


Immutability is the first biggest gotcha coming from OOPS. Can’t reuse the same variable inside the same function, takes sometime to get used to… :wink:


You may have already given us feedback, but if not, I’d definitely like to hear more about what caused you to move from rebar3 to, and then to mix.


Interesting, hadn’t seen that feature before. Certainly possible to hack that in to a rebar3 provider, simply read that line and use a regex to get the test name.


Would be awesome. Part of what makes it work is that on all test failures the path to that line in the test file is printed along with the line in the test that failed assert. This makes it easy to just paste the specific failing test into the mix command


I’m not convinced it’s that simple in all cases. For simple foo_test/0 unit tests, that would probably work fine. But, if you’re doing something more complicated, like foreach, I think this might get brittle quite quickly.

Also note that eunit tests have names that don’t have to agree with the name of the function that implements the test.

It might make sense to see if some extra functionality could be added to OTP to support this use case.


We had an email conversation about it a few years back. Short version: we have an umbrella that builds multiple releases from different combinations of top-level app and leaf app.

Rebar3 (at the time, at least) made it hard to wrangle that. One of my then colleagues wrote GitHub - alinpopa/rebar3-localdep-plugin: Rebar3 plugin to enable local dependencies, which made it work, but it built everything multiple times, so it was quite slow. was significantly quicker, but was (is?) lacking in dependency management, which made our builds brittle.

So we moved to mix. At this point, we’re unlikely to move back to rebar3, because the project’s considered mature, and we’re not planning to do anything major to it.


Ah, I vaguely recall this now, thanks.

For others reading, rebar3 has checkouts (Dependencies | Rebar3) instead of supporting local paths for dependencies. They work great (far better in my opinion) for cases like you want to test local modifications to a dependency in a project, but not at all as a general purpose local dep resource.

I’ll have to dig up the emails but based on this I’m guessing it was something with wanting to only build specific apps – like by cd’ing into an apps dir and running compile and it picking up the dependencies from the level up by using a local dep relative path – while rebar3 will build all the apps in the umbrella project.

Sounds possibly similar to WhatsApp’s issues with rebar3 when having many many applications and modules in a single repo.

My bias opinion is that our umbrella support is better (and simpler) than mix's :), so I may have to ping you to learn more about how you have it working with mix – unless it is just the use of a local path for deps allowing you to cwd to an app and build it and its deps without building everything else?


1 based indexing in strings?


For me one of the gotchas was definitely scope of variables in if/case/receive


I don’t think there’s need for extra functionality in OTP, but it’s not as simple as just a regex either.

However, it’s definitely doable with processing the AST of the test module and using the line numbers from annotations to choose the right test to run.


I did a little meetup talk about Erlang Gotchas back in 2014, which is mostly still relevant (except for the part about parameter modules, but that’s a nice little slice of history there for ya).

Here are the slides and the video (if you’re up for watching all 48 minutes of it).