Elixir Gotchas
pragtob.wordpress.com
pragtob.wordpress.com
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.
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.
Disclaimer - I am still learning both - I am no expert on either - and I am still strugling!
(Calling erlang from elixir much eaiser!)
I really wish that someone would magically transpile all of ERTS so the documentation syntax was uniform.
Elixir is almost more of a guest syntax than it is a diff language.
> 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.
So hopefully that will reduce the confusion!
Erlang/OTP 27 [erts-15.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]
Interactive Elixir (1.17.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> defmodule X, do: defstruct [:a]
{:module, X,
<<70, 79, 82, 49, 0, 0, 7, 128, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 244,
0, 0, 0, 22, 8, 69, 108, 105, 120, 105, 114, 46, 88, 8, 95, 95, 105, 110,
102, 111, 95, 95, 10, 97, 116, 116, 114, ...>>, %X{a: nil}}
iex(2)> x = %X{a: 1}
%X{a: 1}
iex(3)> x[:a]
** (UndefinedFunctionError) function X.fetch/2 is undefined (X does not implement the Access behaviour
You can use the "struct.field" syntax to access struct fields. You can also use Access.key!/1 to access struct fields dynamically inside get_in/put_in/update_in)
X.fetch(%X{a: 1}, :a)
(elixir 1.17.1) lib/access.ex:322: Access.get/3
iex:7: (file)
iex(4)> get_in(x, [:a])
** (UndefinedFunctionError) function X.fetch/2 is undefined (X does not implement the Access behaviour
You can use the "struct.field" syntax to access struct fields. You can also use Access.key!/1 to access struct fields dynamically inside get_in/put_in/update_in)
X.fetch(%X{a: 1}, :a)
(elixir 1.17.1) lib/access.ex:322: Access.get/3
iex:7: (file)
iex(5)> get_in(x, [Access.key!(:a)])
1 get_in(x.a)
better example would be nested. get_in(x.a.b.c)I'm sure everyone who has used Elixir has been bitten by the list of numbers to string conversion.
https://elixir-lang.org/install.html
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.
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.
There are also easy workarounds to that (including NIFs), I personally never needed arrays in Elixir
Of course if your goal is to re-implement sorting algorithms that were designed for mutable memory, you will be disappointed.
This isn't a deal-breaker. If you want a platform language, use that. But for web, you'd be hard-pressed to find something better suited than Elixir.
Just not used across the language
Tuples and binaries give O(1) read access, so depending on your use case, they may be better.
Also look at zippers, finger trees and ropes for more dynamic use, especially local operations (cursors).
https://www.erlang.org/doc/system/system_limits
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.
https://github.com/erlang/otp/releases?q=27&expanded=trueIt should be possible to add Elixir syntactic sugar to make this more concise and natural.
O(1) for reading I believe. The slightly awkward array module is built on top of tuples, a 10-tree of tuples? or something like it.
But good point, once in a while I see list_to_tuple to provide faster indexed reads on lists.
https://www.erlang.org/doc/apps/stdlib/array.html
https://hexdocs.pm/arrays/Arrays.html
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
https://elixirforum.com/t/elixir-array-like-data-structure/2...
That's exactly what JavaScript does (as I understand it), but it hides it from you. And the implementation authors have optimized it over the years.
https://stackoverflow.com/questions/5048371/are-javascript-a...
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.