I remember benchmarking the iterators back when they were first introduced. My conclusion was that because they yield {key, value, next} tuples, while all elixir APIs expect {key, value} tuples, the packing & unpacking of those tuples becomes prohibitively expensive. This might no longer be an issue, so it could use some fresh benchmark, though I would be very surprised if things improved in any significant way.
Michał. From: elixir-lang-core@googlegroups.com <elixir-lang-core@googlegroups.com> Date: Thursday, 14 January 2021 at 08:46 To: elixir-lang-core@googlegroups.com <elixir-lang-core@googlegroups.com> Subject: Re: [elixir-core:9957] [Proposal] Surface Erlang's maps:map function Eksperimental, it is faster to build a list and call maps:from_list/1 than build the map as we go forward. Also, please note maps:map/2 is implemented using maps:iterator/1 and maps:from_list/1: https://github.com/erlang/otp/blob/master/lib/stdlib/src/maps.erl#L374-L379 - so we can implement our own maps:map/2 that keeps our function arity. All that said, if we want to make things faster, then we should evaluate changing Enumerable.Map to use iterators. But we would need extensive benchmarks to check if it is worth it. On Thu, Jan 14, 2021 at 5:55 AM Austin Ziegler <halosta...@gmail.com<mailto:halosta...@gmail.com>> wrote: Building `Map.new/2` on `maps:map/2` would be incompatible, because the transformation function differs in arity (`/1` for `Map.new/2` and `/2` for `maps:map/2`). It would be possible to build `Map.new/2` such that it can tell the difference between a `/1` or a `/2` when the first function is itself a map or struct…but I’m not sure that would be an improvement, and it would lead to potentially confusing documentation on when a `/2` could be passed to `Map.new/2` and when a `/1` could be passed to `Map.new/2`. If something is to be done, I believe that the original proposal, surfacing `maps:map/2` as `Map.map/2` with the arguments flipped for pipeline use _might_ be the best choice. At the same time, I’m not _entirely_ sure that would be useful, as most pipelines transform maps into lists and `maps:map/2` borks on a list: ```elixir iex(1)> :maps.map(fn k, v -> v * 2 end, [{:a, 1}, {:b, 2}]) warning: variable "k" is unused (if the variable is not meant to be used, prefix it with an underscore) iex:1 ** (BadMapError) expected a map, got: [a: 1, b: 2] (stdlib 3.12.1) maps.erl:247: :maps.map(#Function<13.126501267/2 in :erl_eval.expr/5>, [a: 1, b: 2]) ``` At this point, even though I am happy to have discovered `maps:map/2` from this discussion, that this would _not_ improve the usability of Elixir on map transformation. A different question: how can we make these rich Erlang functions much more visible to Elixir users like myself? I don’t care that the arguments are “backwards” from the pipeline, because `maps:map/2` is _incredibly_ useful and will improve some code that I have in production. -a On Wed, Jan 13, 2021 at 7:54 PM eksperimental <eksperimen...@autistici.org<mailto:eksperimen...@autistici.org>> wrote: Great finding. Regardless the benchmarks, Map.new/2 should be optimized for maps using :maps.map/2, because as of now we are doing: map |> Enum.to_list() |> reduce list |> :lists.reverse() |> :maps.from_list() On Tue, 12 Jan 2021 14:09:26 -0800 (PST) "jonar...@gmail.com<mailto:jonar...@gmail.com>" <jonarnet...@gmail.com<mailto:jonarnet...@gmail.com>> wrote: > This usage of Map.new/2 is news to me (pun somewhat intended) and > pretty neat! However, I think that the naming alone may make it less > discoverable and a bit harder to grok when first encountered. There > also *might* be some performance gains from using Erlang's maps:map > for this task instead of maps:from_list but I'm not sure. I'll do > some profiling and find out. > > On Tuesday, January 12, 2021 at 5:01:51 PM UTC-5 > halos...@gmail.com<mailto:halos...@gmail.com> > wrote: > > > It’s not implemented with maps:map/2, but Map.new/2 should do the > > trick. > > > > `Map.new(map, fn {k, v} -> {k, v * 2} end)` > > > > That said, `maps:map/2` is available: > > > > `:maps.map(fn _k, v -> v * 2 end, %{x: 1, y: 2, z: 3})` > > > > It might be worth exploring whether `Map.map` would be > > useful/efficient enough to add for piping purposes. > > > > -a > > > > On Tue, Jan 12, 2021 at 4:51 PM > > jonar...@gmail.com<mailto:jonar...@gmail.com> > > <jonar...@gmail.com<mailto:jonar...@gmail.com>> wrote: > > > >> A common task is to iterate over a map performing some operation > >> thereby producing a new map. There are some ways to do this in > >> Elixir presently, the simplest probably being for...into: > >> > >> for {key, val} <- map, into: %{} do > >> {key, val * 2} > >> end > >> > >> Enum.reduce/3 is also an option. However, Erlang provides a simple > >> function to replace the values of a map with maps:map function: > >> > >> maps:map(fun(Key, Val) -> 2 * Val end, Map) > >> > >> I think an equivalent of this in Elixir would be very useful > >> either as Map.map/2 or Map.transform_values/2 like so: > >> > >> Map.transform_values(map, fn {_key, val} -> val * 2 end) > >> > >> I'm interested to hear if the community considers this a > >> worthwhile addition! > >> > >> -- > >> > > 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-co...@googlegroups.com<mailto:elixir-lang-co...@googlegroups.com>. > >> To view this discussion on the web visit > >> https://groups.google.com/d/msgid/elixir-lang-core/d843c44b-e658-4d71-bb66-00c1e0a21ef7n%40googlegroups.com > >> <https://groups.google.com/d/msgid/elixir-lang-core/d843c44b-e658-4d71-bb66-00c1e0a21ef7n%40googlegroups.com?utm_medium=email&utm_source=footer> > >> . > >> > > > > > > -- > > Austin Ziegler • halos...@gmail.com<mailto:halos...@gmail.com> • > > aus...@halostatue.ca<mailto:aus...@halostatue.ca> > > http://www.halostatue.ca/ • http://twitter.com/halostatue > > > -- 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<mailto:elixir-lang-core%2bunsubscr...@googlegroups.com>. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/5fff9633.1c69fb81.eec7e.37f2SMTPIN_ADDED_MISSING%40gmr-mx.google.com. -- Austin Ziegler • halosta...@gmail.com<mailto:halosta...@gmail.com> • aus...@halostatue.ca<mailto:aus...@halostatue.ca> http://www.halostatue.ca/ • http://twitter.com/halostatue -- 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<mailto:elixir-lang-core+unsubscr...@googlegroups.com>. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAJ4ekQvW-UNQC3pORyb-D4hGCTPvupkT%2Bp53KSkTj8bknj%3Dqgg%40mail.gmail.com<https://groups.google.com/d/msgid/elixir-lang-core/CAJ4ekQvW-UNQC3pORyb-D4hGCTPvupkT%2Bp53KSkTj8bknj%3Dqgg%40mail.gmail.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<mailto:elixir-lang-core+unsubscr...@googlegroups.com>. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LKSMDNM%3DbvXg68tpgQzqMxPEBaVzf96dishNuhutcCsg%40mail.gmail.com<https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LKSMDNM%3DbvXg68tpgQzqMxPEBaVzf96dishNuhutcCsg%40mail.gmail.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/DB7PR07MB38993DAE97190A63FBD5FD14FAA80%40DB7PR07MB3899.eurprd07.prod.outlook.com.