[Proposal] Add Access.get_lazy/3

68 views
Skip to first unread message

Tobias Pfeiffer

unread,
Jul 31, 2024, 2:10:43 AMJul 31
to elixir-l...@googlegroups.com
Hello beloved core team,

TLDR; Should we have Access.get_lazy/3 ?

As usual I'm sure there is some reason why this doesn't exist yet but I don't know so here is the question/proposal:

We have Map.get_lazy/3 and Keyword.get_lazy/3 - they're amazing and helpful. Access basically encapsulates the 2 and I generally use it where I can to allow both Keywords and Maps - most commonly when I deal with options. It doesn't have get_lazy/3 though, which sometimes makes me fall back to either Map or Keyword (or wrap it myself).

Using Access.fetch/2 it should also be easy to implement.

So, would a PR implementing Access.get_lazy/3 be considered?

Thanks!
Tobi

José Valim

unread,
Jul 31, 2024, 2:39:29 AMJul 31
to elixir-l...@googlegroups.com
Hi Tobi, can you provide some context of how it would be used, code wise? Which problem are you facing?

--
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/CAG3Z5YQYuv8SF81vs8UNhtpGN3wA0NHgH1yFhixuwoQmV2S8eQ%40mail.gmail.com.

Tobias Pfeiffer

unread,
Jul 31, 2024, 2:23:01 PMJul 31
to elixir-l...@googlegroups.com
Heyo José,

in most cases it's just a helper method with optional args - which I like to keep in a way that users of it can user either a map or keyword args.

In this particular case it was this helper for tests:

@supply_tag 744_306
def my_helper(opts \\ []) do
query_string = Keyword.get_lazy(opts, :query_string, &build_query_string/0)
supply_tag = Access.get(opts, :supply_tag, @supply_tag)
ip = Access.get(opts, :ip, "68.235.110.20")

"https://some.url#{supply_tag}#{query_string}&ip=#{ip}"
end

build_query_string/0 takes some time but not a lot - but it could also take more time aka the classical get_lazy/3 use case.

Using Keyword.get_lazy/3 here works but limits callers to use keywords (or do a Map to Keyword conversion) which limits the usefulness of `Access` to me - as I tend to prefer to use it when both maps and keyword lists seem acceptable.

Cheers + thanks,
Tobi

José Valim

unread,
Jul 31, 2024, 2:28:04 PMJul 31
to elixir-l...@googlegroups.com
I see. It seems to be a narrow use case for now, so I think Access.fetch/2 is the way to go until we get more evidence that many folks need something similar. My impression is that the direct Access functions are not that commonly used in general. :)

Jay Rogov

unread,
Aug 1, 2024, 6:00:06 AMAug 1
to elixir-lang-core
I think it can pretty much be substituted with `data[key] || expensive_fun()`, can it not? (apart from the case when key actually points to `nil` value)

The only benefit of this added function I see is improved readability when piping, but it's still possible to do without it:
```
iex(1)> data = %{a: 3}
%{a: 3}
iex(2)> data[:a]
3
iex(3)> |> Kernel.||(:rand.uniform)
3
iex(4)> data[:b]
nil
iex(5)> |> Kernel.||(:rand.uniform)
0.764306455162276
```

Tobias Pfeiffer

unread,
Aug 8, 2024, 11:06:18 AMAug 8
to elixir-l...@googlegroups.com
To me, this function is one of the main reasons I'm not using Access more often. I guess I'm a bit confused about the design of `Access` - I'd sort of guess that the goal would be to largely have feature parity with keyword lists and maps when it comes to reading values at least. I think if we wanted to up the usage of Access (which imo would be a good thing) then that'd be great.

As per usual, I do trust your judgement on these though.

Tobias Pfeiffer

unread,
Aug 8, 2024, 11:08:47 AMAug 8
to elixir-l...@googlegroups.com
You're correct, my thing with all of this is just that we already have these functions when working with the specific data types. To me it makes sense to have the same function available when using the module that (mostly) wraps these. The added benefit isn't just readability imo, but also familiarity with the function and that it'd then also work with other types that implement Access, as [] doesn't work on structs.

José Valim

unread,
Aug 8, 2024, 11:14:44 AMAug 8
to elixir-l...@googlegroups.com
That's a good question. To me, Access is mostly the backend that is used for the brackets plus get_in/update_in/pop_in. It is not primarily meant to be invoked directly, unless you truly need to write a lazy fetch that works against keywords and maps. Which do not sound very common in practice.

I also think the keywords vs maps vs structs is a common confusion point and I am curious to see if the type system will give us more affordances around those cases and better guidelines.

Tobias Pfeiffer

unread,
Aug 9, 2024, 5:44:03 AMAug 9
to elixir-l...@googlegroups.com
Interesting to read! I always thought, we ought to use Access more when we only care that we have a "basic" Key/Value structure. If that's what it's intended for, maybe we could make that a bit more apparent in the docs? That said, all the main module docs use are the function related to key access (aka not Access.get/3 & Access.fetch/2) so it isn't actively advertised. To me it just always felt like, that if I have a module that easily allows me to work with both then it's an easy & cheap win in case I change my mind. Would be good to know more prominently if they are not intended that way, just an idea.

Thanks for engaging and explaining as always!

Reply all
Reply to author
Forward
0 new messages