I recognize more use cases than mine. Given we will not change Kernel.get_in, I have ideas for other, less "nillable" names, such as "get_path" or "path_in" to make mil-safety less of an exceptional situation. Path expressions, as originally used in object oriented databases, typically did not raise exceptions when some data did not match expectations. This specific naming discussion can be deferred though.
I am in agreement on writing assertive code. That is the very reason I want something in the standard library that is a nil-safe navigation through untrusted input. I don't want to write an `if` or `with` dealing with each list key that might be nil, when I don't have to do it for maps. It it is the very reason I view the dot syntax as very confident keys exist vs. a get_in call which uses Access to determine existence of keys/lists. -Greg Vaughn > On Feb 7, 2020, at 6:55 PM, José Valim <[email protected]> wrote: > > > What I find curious is that once we implement Kernel.nillable_get_in, why > > would anyone choose to use Kernel.get_in instead? > > When I don't expect anything to be nil, I want it to fail as soon as > possible, instead of having nil further creeping into the system. Personally, > most of the times I used get_in and friends, I am working with structured > data (the opposite of your use case). If any nil shows up, it should be an > error. > > And changing get_in may not break code, expectations I had when I wrote the > code would certainly be broken. And I would personally be unhappy if we > simply changed get_in without introducing an option to write assertive code. > Writing assertive code is an important of Elixir. It is why we have map.foo > in addition to map[:foo]. So I think it is best to remove changing get_in > from the discussion altogether, I don't see it happening. > > We can continue discussing alternatives though. > > > > On Sat, Feb 8, 2020 at 1:47 AM Greg Vaughn <[email protected]> wrote: > 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. > > -- > 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/CAGnRm4K-yXsZ2mxJ3sg6knRwLAFmMUky6c0G50gaBVnDpb18fA%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/E9C59B12-1663-45E9-A8C3-163F75895D52%40gmail.com.
