One more point. Even if my proposal is not accepted, these docs for
Kernel.get_in really need to change
In case any of the entries in the middle returns nil, nil will be returned as
per the Access module:
iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["unknown", :age])
nil
The Access module guarantees no nil-safety. It's an "accident" that Access.get
does.
-Greg Vaughn
> On Feb 7, 2020, at 4:40 PM, José Valim <[email protected]> wrote:
>
> Hi Greg, I have been thinking more about this too, and I think there are some
> neat ways we can make this more accessible:
>
> We could introduce Access.nillable (please suggest a better name) that you
> would use like this:
>
> get_in(root, Access.nillable([:foo, :bar, Access.at(0)]))
>
> Basically, it traverses the path and sets all functions in the path to
> something that handles nil. In your apps, you can quickly encapsulate it like
> this:
>
> nillable_get_in(root, [:foo, :bar, Access.at(0)])
>
> It is concise, backwards compatible, and clear in intent.
>
> Thoughts?
>
> On Fri, Feb 7, 2020 at 11:35 PM Greg Vaughn <[email protected]> wrote:
> I just wanted to follow up and summarize here. I submitted a PR
> https://github.com/elixir-lang/elixir/pull/9773 with some more discussion,
> but the core point there was that we needed more discussion on the core list
> before a PR and it was closed. Nil-safety by default is undesirable in more
> Access functions than Access.get.
>
> I'm exploring this on my own in my own codebase as I rework all the get_in
> calls I assumed were nil safe despite using Access.at. I am quite against a
> solution that is more verbose to gain mil safety as I use this at the edges
> of my system in an anti-corruption-layer. I'd rather see this implemented
> once, well, in the standard library than expect thousands of projects to do
> it themselves or bring in a 3rd party solutions to achieve it.
>
> Feel free to discuss some more.
>
> -Greg
>
> > On Jan 30, 2020, at 12:02 PM, Allen Madsen <[email protected]> wrote:
> >
> > I'm in favor of them being nilsafe by default.
> >
> > Allen Madsen
> > http://www.allenmadsen.com
> >
> >
> > On Wed, Jan 29, 2020 at 11:24 AM Tor Bjornrud <[email protected]> wrote:
> > I wouldn't mind having opts for something like this. Avoids creating a
> > slew of Access functions that then become difficult to sift through.
> >
> > %{"items" => nil} |> get_in(["items", Access.at(0, nilsafe: true)
> >
> > On Tuesday, January 28, 2020 at 8:10:04 PM UTC-6, Greg Vaughn wrote:
> > Thanks, José. I agree with the need to be consistent. I will look at the
> > bigger picture, though, like Manfred I find the addition of "maybe" to be
> > awkward, so my preference is to have the existing recommended functions in
> > the Access module intended for use with get_in to be consistently nil safe.
> > I'm open to more ideas, too.
> >
> > -Greg Vaughn
> >
> > > On Jan 28, 2020, at 12:45 PM, José Valim <[email protected]> wrote:
> > >
> > > The proposal is reasonable however it would introduce an inconsistency
> > > since the other selectors in Access, such as Access.key, are also not nil
> > > safe. So whatever solution we choose needs to be consistent.
> > >
> > > One possible suggestion is to introduce a "Access.maybe" that composes
> > > but composition would have to be back to front:
> > >
> > > %{"items" => nil} |> get_in(["items", Access.at(0) |> Access.maybe])
> > >
> > > Another idea is to introduce maybe_at, maybe_key, maybe_key! and so on.
> > > But I am not sure if this is desirable. Thoughts?
> > >
> > > On Tue, Jan 28, 2020 at 7:33 PM Greg Vaughn <[email protected]> wrote:
> > > I propose that the function returned from Access.at/1 special case nil
> > > such that the overall Kernel.get_in/2 call returns nil instead of raising
> > > an error.
> > >
> > > Rationale:
> > > I originally blamed this on Kernel.get_in/2 and I'd like to thank Eric
> > > Meadows-Jönsson for explaining the underlying reason to me on Slack.
> > >
> > > I like to think of Kernel.get_in/2 as a nil-safe way of plucking values
> > > out of nested data structures, but I learned today that is only partially
> > > correct. The nil-safety comes from the underlying Access.get/2 calls. The
> > > docs for get_in includes:
> > >
> > > In case any of the entries in the middle returns nil, nil will be
> > > returned as per the Access module:
> > > iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
> > > iex> get_in(users, ["unknown", :age])
> > > nil
> > >
> > > and I expected use of Access.at/1 in my keys to act similarly, but it
> > > doesn't. For example:
> > >
> > > iex(185)> %{"items" => ["desired_value"]} |> get_in(["items",
> > > Access.at(0)])
> > > "desired_value"
> > > iex(186)> %{"items" => nil} |> get_in(["items", Access.at(0)])
> > > ** (RuntimeError) Access.at/1 expected a list, got: nil
> > > (elixir) lib/access.ex:663: Access.at/4
> > >
> > > I propose that the function returned from Access.at/1 special case nil
> > > such that the overall get_in/2 call returns nil instead of raising an
> > > error. I have not dug into the source yet but I'm happy to work up a PR
> > > if there is interest in this change.
> > >
> > > -Greg Vaughn
> > >
> > > --
> > > 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 [email protected].
> > > To view this discussion on the web visit
> > > https://groups.google.com/d/msgid/elixir-lang-core/6B6AB775-F3D5-40E5-BFBD-9852FBCBD1D0%40gmail.com.
> > >
> > >
> > > --
> > > 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 [email protected].
> > > To view this discussion on the web visit
> > > https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4KZPZ5mpP6SSzhmq3jpuZBYA1irpmOa19UNH2fS_3QKQA%40mail.gmail.com.
> > >
> >
> >
> > --
> > 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 [email protected].
> > To view this discussion on the web visit
> > https://groups.google.com/d/msgid/elixir-lang-core/1ae0b9d3-9471-4750-8734-281033e9a1dc%40googlegroups.com.
> >
> > --
> > 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 [email protected].
> > To view this discussion on the web visit
> > https://groups.google.com/d/msgid/elixir-lang-core/CAK-y3Cu%2BGBO1RWsdAjAHoaukV3w4QJPPdqqNU_miQ_%3Dv5%3DdDeQ%40mail.gmail.com.
>
> --
> 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 [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/elixir-lang-core/22988265-AB94-4666-894B-9ECF7B87905D%40gmail.com.
>
> --
> 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 [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2B5ovo9YdQHQO2m6i%3DL_SxPKRN4O4fZejH%3DXMXfJWwWkQ%40mail.gmail.com.
--
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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/elixir-lang-core/4CE0D4F8-A341-4832-AC94-BDBC0D7E0911%40gmail.com.