Re: [elixir-core:9364] PROPOSAL: Nil-safe Access.at/1

2020-02-07 Thread José Valim
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  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 
> 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 
> 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  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  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 elixir-l...@googlegroups.com.
> > > To view this discussion on the web visit
> https://groups.google.com/d/msgid/elixir-lang-core/6B6AB775-F3D5-40E5-BFBD-9852FBCBD1D0%40gmail.com.
>
> > >
> > > --
> > > 

Re: [elixir-core:9363] PROPOSAL: Nil-safe Access.at/1

2020-02-07 Thread Greg Vaughn
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  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  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  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  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 elixir-l...@googlegroups.com. 
> > 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 elixir-l...@googlegroups.com. 
> > 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 

Re: [elixir-core:9367] PROPOSAL: Nil-safe Access.at/1

2020-02-07 Thread José Valim
> 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  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  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  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 
> 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 
> 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 
> 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 
> 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.
> 

Re: [elixir-core:9365] PROPOSAL: Nil-safe Access.at/1

2020-02-07 Thread Greg Vaughn
Hi José, I have considered that as one possibility too. From Eric's comments I 
don't belive the Access module is the correct place to implement it though. 
Personally, I don't care what the module is called because I am prepared to 
create my own module to handle this.

What I find curious is that once we implement Kernel.nillable_get_in, why would 
anyone choose to use Kernel.get_in instead? Who wants to opt into 
nil-exceptions (Tony Hoare's billion dollar mistake)? We have other means, such 
as the dot syntax (my_struct.atom_key.sub_key) when we have confidence those 
keys exist and we want to "let it fail" if they don't. Kernel.get_in should be 
used only when we have tentative expectations of a data structure.

I use this when dealing with untrusted 3rd party json data on the edge of my 
system. Some fields that typically should be a list might be missing or present 
but nil until some state transition and they transition to an explicit field 
with a list value that Access.at can traverse.

I accept the argument that only something new like nillable_get_in is backwards 
compatible, but I wonder how valuable the backwards compatible get_in 
implementation is. There is support in this thread for mil-safety (or 
nil-ignorance as once presented) by default. I'm left wondering how many 
production systems rely upon nil exceptions during Kernel.get_in calls for 
proper behavior that would fail if we made it nil-safe by default.

-Greg Vaughn


> On Feb 7, 2020, at 4:40 PM, José Valim  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  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  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  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  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  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 

Re: [elixir-core:9366] PROPOSAL: Nil-safe Access.at/1

2020-02-07 Thread Greg Vaughn
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  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  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  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  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  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  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 

Re: [elixir-core:9368] PROPOSAL: Nil-safe Access.at/1

2020-02-07 Thread Greg Vaughn
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  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  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  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  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  
> > > 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  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 

Re: [elixir-core:9369] PROPOSAL: Nil-safe Access.at/1

2020-02-07 Thread José Valim
For now, I don't think we should add a new function to Kernel. So we should
find something that makes a path nillable for definition in Access, and
then you can define get_path in your app if that's what you prefer.

On Sat, Feb 8, 2020 at 2:23 AM Greg Vaughn  wrote:

> 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  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  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  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  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 
> 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 
> 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