This would be more helpful if it dove into the Erlang side, as many of these "gotchas" are due to how Erlang and the BEAM work, and Elixir, being built on top of it and binary-compatible with the entire ecosystem, necessarily exhibits these behaviours.
Keyword lists, charlists vs strings (actually called binaries) [1], empty map matching all maps are obvious if you look at how they work in Erlang.
I haven't written a single line of Erlang though I can grok it pretty well by now. Knowing the entire platform is how you become a productive Elixir programmer, though it seems some devs refuse to look behind the curtains to understand the Erlang side of it, thus never truly understand the power of the BEAM platform.
---
1: I admit I still unsure about the separation of charlists and binaries. As far as I understand it, binaries are stored in their own heap to avoid copying when sending across processes, so are ideal for sharing large payloads, and charlists are not great for UTF-8 content, as they simply are a naive list of integers (hence one of the gotchas). Erlang uses charlists a lot for "string" content.
Elixir made the right choice to use binaries for strings, as they can ensure they are correctly encoded, provide high-level API to deal with the intricacies of Unicode, and still retain compatibility with Erlang by providing charlists and raw binaries for non-UTF-8 data.
> Knowing the entire platform is how you become a productive Elixir programmer, though it seems some devs refuse to look behind the curtains to understand the Erlang side of it, thus never truly understand the power of the BEAM platform.
This should be a lesson learned by all that boost about Scala, Kotlin, Clojure, F#, C and C++ replacements, JavaScript replacement, without bothering to learn the underlying infrastructure they are build upon.
Many times the X is going to replace Y advocacy, is a bit hard to achieve when the platform was designed for Y and will never go away from Y, for its whole lifetime.
Agreed, even with f# a first class citizen in the .net world, written, maintained and distributed by Microsoft, I still have needed to gain a working knowledge of c# to properly interact with the .net libs and third party libs (which I absolutely need to do as the f# ecosystem is tiny compared to c#). So at the end of the day I needed to learn two languages to atain my goal of learning one enough to be useful.
Disclaimer - I am still learning both - I am no expert on either - and I am still strugling!
Also, elixir team decided to deprecate single-quotes for charlists. No more single quotes (charlist, only for erlang interop) vs double quotes (binary string, used everywhere in elixir) surprises
> The other mystery here are the 2 different syntaxes in use for charlists – single quotes ('charlist') vs. the ~c"charlist" sigil. That’s a rather recent development, it was changed in Elixir 1.15, after some discussion …
>
> So, it’s now less confusing but still confusing – which is why it made this list.
Charlists with single quotes are deprecated since Elixir 1.17 - the ~c[…] sigil should always be preferred.
Are these even gotchas if they are all very well documented in the official documentation already? I was expecting to see some unusual or undocumented behaviours...
Unless you are fine letting old homebrew work its "magic" - the installation is too lengthy and involved for a new language. It should just be click, download:
That is the biggest gotcha for me. There doesn't seem to be a simple installer or binary you just get up and running unlike other major languages. Is it a distribution issue with erlang or something? I'd have thought it'd be easy to package it up.
Not requiring a package manager is the point. Python, node, Zig etc supply binaries or a binary installer for each major OS, so why not Elixir? I can't see how it'd be a bad thing for anyone.
I imagine that part is slightly complicated by the fact that it requires host language runtime (Erlang). Elixir compiled with one version of OTP is not necessarily compatible with another version so supporting binaries for N versions of Elixir becomes NxM problem when you factor in OTP versions, plus supporting distribution of OTP binaries is probably complicated in itself. If there is a problem with OTP, users would swarm first party distributor, but their ability to help would be very limited.
many functional languages (if not all) do not have arrays (intended as a contiguous areas of memory containing indexable elements of fixed size) they are usually left as an implementation as libraries (i.e. Haskell's Data.Array)
There are also easy workarounds to that (including NIFs), I personally never needed arrays in Elixir
Not disagreeing with you, but it's worth noting that tuples support random O(n) access by index. They can therefore be used in place of arrays for some simple applications.
There is also some hope that future versions
of the Erlang compiler will allow mutable O(1)
update of tuple elements through setelement
(code inside a process is - almost - guaranteed
not to have shared references).
Safe destructive update of tuples has been implemented
in the compiler and runtime system. This allows the VM to
update tuples in-place when it is safe to do so, thus
improving performance by doing less copying but also by
producing less garbage.
Also, if it's read heavy, you can use use tuples for O(1) access.
Besides all that, the community is extremely helpful, if you have questions check out the forum, for example on this very topic there's quite a bit of helpful discussion
That is the curse of guest languages, either they have to deal with leaky abstractions, or have to create their own, slower, implementation on top of platform primitives.
Also why with time, I learned to stay with platform languages, even if they aren't as shinny, or have warts that in hindsight could have been done better.
Keyword lists, charlists vs strings (actually called binaries) [1], empty map matching all maps are obvious if you look at how they work in Erlang.
I haven't written a single line of Erlang though I can grok it pretty well by now. Knowing the entire platform is how you become a productive Elixir programmer, though it seems some devs refuse to look behind the curtains to understand the Erlang side of it, thus never truly understand the power of the BEAM platform.
---
1: I admit I still unsure about the separation of charlists and binaries. As far as I understand it, binaries are stored in their own heap to avoid copying when sending across processes, so are ideal for sharing large payloads, and charlists are not great for UTF-8 content, as they simply are a naive list of integers (hence one of the gotchas). Erlang uses charlists a lot for "string" content.
Elixir made the right choice to use binaries for strings, as they can ensure they are correctly encoded, provide high-level API to deal with the intricacies of Unicode, and still retain compatibility with Erlang by providing charlists and raw binaries for non-UTF-8 data.