Enum always returns lists by design, because it was designed to be a single abstraction that can:
1. enumerate elements while skipping 2. support both eager and lazy with the same protocol 3. support halting (such as take) 4. support zipping 5. does not cause dangling resources (so you can work with files) Many resources and operations above do not work with the concept of returning the same data structure. For example, how do I return the same data-structure for Enum.map(1..10, &:rand.uniform/1)? Or for an io stream? Or for a repo stream? Not even something as simple as: Enum.map(map, fn {_, v} -> v * 2 end)? So when exactly Enum.map would return a map data structure? And, as you said, this would be majorly backwards incompatible. What you want to achieve needs to be done by a new protocol and a new API. So I recommend exploring it within the context of your library. :) On Mon, Oct 16, 2023 at 9:23 AM Mihai Potra <m...@mpotra.com> wrote: > The *Enum module* currently in many of its defined functions (i.e. > *reject/2*) relies on lists and forces *Enumerable* implementations to > operate and returns lists. > > One example of this is the *Enum.reject/2* function that operates with > *Enumerable.reduce/3* but then it pipes everything into *:lists.reverse/1. > *This forces all *Enumerable* implementations to return lists so that > *Enum.reject/2* always returns a list. > > Ideally, *Enum* module would work with any *Enumerable* implementation > and its function return the Enumerable data type that the implementation > provides. Having Enum conform to operating with Enumerables this way would > allow less friction in working with enumerables and better support for > implementing Enumerable/Collectable concepts with structs and data types. > > As an example, removing a key or key-value from a map would be a simple > *Enum.reject* call instead of piping the map into the Enum.reject/2 and > then into a list to map conversion. > I've stumbled upon this while writing a library that would operate with > Source and Sinks as enumerables and collectables to allow for all sorts of > predefined types and custom defined structs, and got blocked at abstracting > away some of its core features. > > The good news is that finding a solutions might not be *that* complicated > and I'd be happy to make a PR for it *(already tried replacing > :lists.reverse/1 with a different function that respects the data type > returned by Enumerable.reduce/3)* > > *Challenges* > The biggest challenge here is obviously backwards compatibility with code > that relies on the Enum functions that return a list to keep returning a > list, so here's where I'd want a discussion and guidance on the best course > of action. As far as I can see, there's three options: > > *1.* Have a new module written out of `*Enum*` (say *Enum2*) and > deprecate Enum in the future - a better module name than just Enum2 is > definitely a must (looking for suggestions). *I suspect this would also > open the door to simplifying the Stream module.* > > *2.* Extend the *Enumerable* protocol to include a `reverse/1` function, > *and* a `new/1` function to replace the empty list constructor `[]` used > by Enum. Need to consider existing user code that implements Enumerable as > it would break without defining these two new functions. > > *3.* Create a new protocol that Enum would use, with fallback to current > behaviour. Best for supporting current user implementations of Enumerable > and keeping current behaviour, but doesn't make sense on the long term. > > Also as a last decision to be made is how to deal with Map. Ideally, Enum > functions would also return a Map if the enumerable is a map, but many rely > on the current behaviour of it returning lists because this has been the > status quo. This makes me favour option 1 of having a new module to replace > Enum in the future. > > Looking forward to hearing your thoughts and suggestions/proposals for how > to best take on this. > > Kind regards, > Mihai > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to elixir-lang-core+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/9d0f6096-43aa-441b-9060-1a4949ff8e67n%40googlegroups.com > <https://groups.google.com/d/msgid/elixir-lang-core/9d0f6096-43aa-441b-9060-1a4949ff8e67n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4JXT7V%2BMnk6i2WFzJZbNQ0G23x14WvhdUG_aXPbxohB5Q%40mail.gmail.com.