Why are reverse/1 and at/1 in Enum?

So is the documentation wrong?

From Keyword lists and maps — Elixir v1.17.2

" Maps’ keys do not follow any ordering."

Or am I misunderstanding what ordering means relative to functionality such as Enum.at/3?

1 Like

It should say “user ordering”. The same map will have a given order within the same VM. PR welcome!

2 Likes

The main argument so far to not have them in Enum is the potential confusion of folks thinking that Enum.delete_at will return the same type as the input, which happens to a few Enum operations already, such as map, filter, split_with, take, and drop.

However, potential confusion is not a very helpful guideline, and there are several functions from List, such as pop_at and flatten, that we could argue adding into Enum.

Luckily, one rule we can use, especially if the functions we are discussing return a list, is: do these functions make sense for Enum and Stream? I don’t think pop_at, replace_at, and update_at are meaningful stream operations.

We can also ask ourselves: does the name reflect a linear operation? delete could be added to both Enum and Stream, but it can be misleading. Someone may think Enum.delete(set, 123) will be an efficient operation, but it is a full blow set traversal, similar to Enum.filter(set, fn x -> x != 123 end). So if the goal is to have more indexed operations, I would rather allow Enum.filter(collection, fn x, index -> ... end) or similar, which will enable other use cases, instead of Enum.delete_at. Or introduce drop_at and take_at, which are at least more inline with Enum naming, allowing one or a list of indexes.

Then there are other functions in List, such as flatten, which does not exist in Enum because few data structures allow arbitrary nesting.

4 Likes

Luckily, one rule we can use, especially if the functions we are discussing return a list, is: do these functions make sense for Enum and Stream? I don’t think pop_at, replace_at, and update_at are meaningful stream operations.

We can also ask ourselves: does the name reflect a linear operation? delete could be added to both Enum and Stream, but it can be misleading. Someone may think Enum.delete(set, 123) will be an efficient operation, but it is a full blow set traversal, similar to Enum.filter(set, fn x -> x != 123 end). So if the goal is to have more indexed operations, I would rather allow Enum.filter(collection, fn x, index -> ... end) or similar, which will enable other use cases, instead of Enum.delete_at. Or introduce drop_at and take_at, which are at least more inline with Enum naming, allowing one or a list of indexes.

This is an interesting insight into how the APIs for these modules are designed. Thanks :slight_smile: