Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

What threw me off with Elixir was multiple inconsistencies, some of which documented in this article (btw, Elixir didn't fix the issue Joe mentioned about FORMS ≠ EXPRESSIONS).

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?)



> 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?)

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...


Ahh, that's it. I said in a sibling comment that I had no idea why it was like that. But reading this made me realize that at one point I did know why! Completely forgot this bit of knowledge in the last year of not using the language.


Oh yeah, FWIW a "built-in" function or macro just means it's a part of the Kernel module, which is automatically required+imported in Elixir modules. So it's not orphaned, it's just in the one special module that gets brought in by default.


I guess it has something to do with those functions frequently used in guards. _Notice tuple_size/1, map_size/1, byte_size/1 and some other functions/macros are defined in Kernel and documented in the section Guards[0]_

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

[0] - https://hexdocs.pm/elixir/Kernel.html#guards


I didn't look it up for this one specifically but usually those are when elixir is just directly applying a function from the core erlang module (ie erlang global fns).

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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: