Elixir's biggest gotchas?

Being new to Elixir would be very valuable to learn what you guys consider to be the biggest gotchas in Elixir land?


For me, it’s the functional programming. Elixir is not the first functional programming I learn. But it’s the first functional programming I learn by doing, not just by reading the books. Another things are like pattern matching, pipe operator, recursive call, etc.


erlang charlists. Newbie exercises are bound to create a list of integers and iex will print it out in a surprising way. It’s a fundamental ambiguity that’s completely understandable, but it introduces itself to newcomers in a very surprising way.


For me the trickiest thing has been new patterns for managing state. The BEAM ecosystem has extraordinarily powerful tools for this, but learning new abstractions for it like the proper use of genservers and supervision trees has been a road with some missteps for me.


Yep–that’s one of those questions that keeps coming up again and again.

1 Like

Allowing rebinding of values leads people new to Elixir to think we allow mutation.

iex> x = 1

iex> x = 2

Perfectly legal and people think it means that someone is mutating x–which they’re not. But this seems to be one of those things that people inevitably see and say “Hey waitaminute–I thought Elixir doesn’t allow mutation? WTF?”

I don’t know that I’d call this a “gotcha” but it does seem to confuse new folks on a fairly regular basis.


For me so far syntax for piping into anonymous function was a bit surprising:
|> (&(&1)).()


I’d say most gotchas are related to OTP and state management—it’s really a whole different beast from the language itself.

Language-level gotchas and common pitfalls include:

  • = is not assignment
  • Using if instead of function pattern matching
  • Lists and keyword lists—a lot of people think they’re the same as their Ruby or JavaScript arrays

Erlang charlists can be confusing but it is not restricted to just erlang charlists. You have exactly the same issue with elixir strings:

iex(1)> <<195,165,195,164,195,182>>

It’s a result of the erlang system only having a fixed set of datatypes and not being able to define your own datatypes, and there is no character or string base type. This means choosing an existing type to use as strings: erlang chose lists which was common in the functional world, while elixir has chosen binaries.



I think Elixir may actually make it slightly more confusing because a lot of folks coming from other language expect 'foo' == "foo". That’s why one of the proposals I want to send after v1.3 is out is to deprecate the use of 'foo' in the long-term (and I really mean long-term) in favor of the sigil ~c"foo". It is going to be more explicit and I find using sigils for char lists in Elixir at this point more idiomatic.


I like that. The experienced developers needing to interact with erlang libs will be comfortable with sigils, and the newcomers won’t have to learn it until later. Brilliant!


The thing that confused me the most in the beginning was the syntactic sugar for Keyword lists. I kept seeing these odd things in the options list for functions and I had no idea what they really were.

IO.inspect Process.list, width: 40

I cargo culted a lot of code until I actually made the connection that line is really.

IO.inspect(Process.list, [{:width , 40}])


I have to say that sometimes some of the syntactic sugar can make things a little more difficult to mentally parse for me. Maybe that’s just me though.


Yeah, the keyword lists sugar for function arguments gets me often. Just have to get used to it I guess.


Agreed on this one. Elixir used to have a ListDict module that was a sort of “superclass” of the current Keyword module that helped to make that explicit. However, once Erlang got large map support, it because superfluous. Now the leap from list to Keyword list has no intermediate step.

The implicit handling of it as the final param in a function call (reminiscent of Ruby) further adds to its mystical quality.

1 Like

… And on top of that, the order of keywords does matter.

def foo(name: name, type: type) will not be matched when calling foo(type: "elephant", name: "Dumbo").


Wow, that doesn’t stop to look confusing no matter how much I look at it :slight_smile: I was actually wondering if something like that is possible, but now that I see it I’m not sure I’d like to know :slight_smile:

Btw, where did you stumble upon that?


Most likely in this situation: Pipe operator and functions (not function calls)

i.e. for an ad hoc parameter reorder to continue the current chain (not recommended).


Y was using to restructure the return value from previous function, but better to write a separate function so things look clean.


If you haven’t seen pattern matching before, that might be difficult to get used to.
This isn’t really a gotcha - it’s one of Elixir’s strengths of course :slight_smile: , but someone new to Elixir would find it difficult to understand a lot of code if they’re unfamiliar with pattern matching.