For me, I run into this often enough, that I wish this was a thing. Clearly, YMMV.
Strictly speaking, yes. But I think just updating the *_lazy versions is sufficient for the level of consistency already present. I mean, there's no Map.put_lazy when there clearly could be and I don't think not changing update makes things worse. (sorry for the double negatives there) The documentation for a revised Map.update would need to be careful. There' would be a lot going on to explain. On Friday, May 19, 2023 at 7:54:46 AM UTC-4 woj...@wojtekmach.pl wrote: > I believe an apples-to-apples comparison would be: > > # before > x > |> then(&Map.put_new_lazy(&1, :file_path, fn -> > Path.join([&1.base_path, &1.filename]) end)) > > # after > x > |> Map.put_new_lazy(:file_path, &Path.join([&1.base_path, > &1.filename])) > > And I think it does read better. > > That being said, personally I don’t think I have commonly needed something > like this though and I’d just break out of a pipe and move on. :) > If we add this precedent, that the function receives the input as one of > the arguments, should we update other functions for consistency too? Do we > have an Map.update accepting a 2-arity function? (Is the map the first or > the second argument?!) > > On 19 May 2023, at 13:30, Christian Trosclair <christian...@dockyard.com> > wrote: > > It is sometimes if not often desirable to build up some Map or Keyword > list and add or update values in such a way that takes into account the > current state of the data, yet some of the current functions do not allow > this to be done from a pipe. > > A trivial example for instance: > ``` > map = %{filename: “thing.txt”} > map = Map.put_new(map, :base_path, "/") > map = Map.put_new(map, :file_path, Path.join([map.base_path, > map.filename])) > > ``` > This is begging to be piped, but Map.put_new_lazy/3’s function argument > does not receive the current map. > > For reference Map.put_new_lazy/3 > > https://github.com/elixir-lang/elixir/blob/a64d42f5d3cb6c32752af9d3312897e8cd5bb7ec/lib/elixir/lib/map.ex#L381 > > It is true we could simply use Kernel.then/2, but I think we can do better > and make code easier to scan. > > An example using pipes and Kernel.then/2 > ``` > %{filename: “thing.txt”} > |> Map.put_new(:base_path, "/") > |> then(&(Map.put_new(&1, :file_path, Path.join([&1.base_path, > &1.filename])))) > > ``` > Kernel.then/2 is breaking up what could be a quick scan of the code. > > We can smooth this out. > > Here is an implementation on Map.put_new_lazy/3 > > ``` > @spec put_new_lazy(map, key, ((map) -> value)) :: map > def put_new_lazy(map, key, fun) when is_function(fun, 1) do > case map do > %{^key => _value} -> > map > > %{} -> > put(map, key, fun.(map)) > > other -> > :erlang.error({:badmap, other}) > end > end > > ``` > Then we could rewrite the original example like: > > ``` > %{filename: “thing.txt”} > |> Map.put_new(:base_path, "/") > |> Map.put_new_lazy(:file_path, &(Path.join([&1.base_path, &1.filename])))) > > ``` > If we wanted to go even further, we could even accept an arity 2 function > and pass in both the map and the key. > > Thoughts? > > > > -- > 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. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/bc728f96-ff11-40c1-b90f-b412e241fbd9n%40googlegroups.com > > <https://groups.google.com/d/msgid/elixir-lang-core/bc728f96-ff11-40c1-b90f-b412e241fbd9n%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/2ea1ed78-45eb-4299-8bfe-2a5f96984709n%40googlegroups.com.