A week with Elixir (2013)
joearms.github.io
joearms.github.io
I know when I'm thinking of the ecosystem, I really think if it more in terms of the broader concept of the BEAM as being "the ecosystem", that common thread, rather than just Elixir, or Erlang, or LFE, of Gleam individually.
Even in this post, he was able to be polite and still critical of Elixir, pointing out parts that annoyed him, but still ended it with positive praise.
Another one is this: When you first learn Elixir, you start to like the idea of calling functions from their types, like Tuple.product({2, 4}). Now if you want to get the size of a tuple, what do you do? Probably Tuple.size(...), right?
Wrong. You should use tuple_size(...)!
Turns out sometimes you gotta use these "orphan" functions even though they logically belong to a certain type (in this case, why isn't tuple_size called like Tuple.size or something?)
As for why they do that, rather than wrap them into the appropriate module, I have no idea. There may be a valid reason: for a language that is otherwise so careful about naming, organization, and consistency it would be a bizarre unforced error.
Some of them have nonstandard (for elixir) names and parameter order too so they are definitely one of the few unpleasant quirks of the language.
tuple_size/1 is a guard, and guards are built-in. The compiler itself uses them. Unlike regular functions, you are allowed to use guards in a function head, like:
def foo(my_tuple) when tuple_size(my_tuple) == 3 do ...
Official docs: https://hexdocs.pm/elixir/1.16.3/patterns-and-guards.html#gu...We can't invoke remote functions (which Tuple.size/1 would have been) in guards.
Though, there are some other functions that I can't think of a reason why they are "orphaned" such as put_elem/3 to put element into a tuple, while, for example, for maps there is Map.put/3