Improving Access for working with nested structs

207 views
Skip to first unread message

Michał Muskała

unread,
Dec 7, 2016, 6:50:26 PM12/7/16
to elixir-lang-core
Good evening everybody.

This is a moved discussion from https://github.com/elixir-lang/elixir/issues/5548#issuecomment-265602755.

Today, there's no way to work with structs in an easy way for the _in functions.

For static keys, everything is nice and shiny when working with both maps and structs:

update_in(foo.bar.buz, &(...))

Unfortunately as soon as we need to introduce a dynamic value, it suddenly becomes extremely clunky in case of structs:

update_in(foo.bar[key], &(...))
# vs
update_in(foo, [Access.key!(:bar), Access.key(key)], &(...))

This is generally pushing me to work more with unstructured data in forms of maps, the usability difference is huge. The Access is a very powerful tool that helps to solve many problems in a concise way, it's unfortunate structs have such a poor support.

Michał.

Adam Kittelson

unread,
Dec 7, 2016, 9:41:23 PM12/7/16
to elixir-l...@googlegroups.com
The other *_in use case that I find clunkier with structs is piping a struct through multiple *_in functions isn’t as nice.

e.g. with a map you can just do

  map
  |> update_in([:some_key, …], &(…))
  |> update_in([:other_key, …], &(…))

but with a struct you have to do something like

  update_in(struct.some_key.etc, &(…))
  |> update_in([Access.key!(:other_key), …], &(…))

I’ve also found myself at times either not defining a struct where I could, or even implementing the Access behaviour on modules that do define a struct by delegating functions to Map if I find myself doing these kinds of pipelines frequently.

Adam



Michał.

--
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+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/4299E5C9-9C9B-411F-90FA-9EF7B6900327%40muskala.eu.
For more options, visit https://groups.google.com/d/optout.

José Valim

unread,
Dec 8, 2016, 4:34:12 AM12/8/16
to elixir-l...@googlegroups.com
I agree this is an issue although I don't have any solution in mind. Proposals are welcome.



José Valim
Skype: jv.ptec
Founder and Director of R&D


Michał.

Ólafur Arason

unread,
Dec 8, 2016, 5:20:25 AM12/8/16
to elixir-lang-core
What is the exact problem I don't get it from the description is it that struts don't have Access built in, because that is solveable, or that because you have default value like nil set in a struct you can't create a nested structure on the fly?

Regards,
Olaf

Allen Madsen

unread,
Dec 8, 2016, 9:08:40 AM12/8/16
to elixir-l...@googlegroups.com
Would it be acceptable and sufficient, when using the defstruct macro, to define default implementations of the methods required for the Access behaviour?
--
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+unsubscribe@googlegroups.com.

José Valim

unread,
Dec 8, 2016, 9:49:52 AM12/8/16
to elixir-l...@googlegroups.com
The above wouldn't be desired because you lose the important property of asserting the field is there. Plus, implementing behaviour means defining three functions, and I don't believe defstruct should pollute the user module with functions more than necessary.

One of the reasons Access was moved to a Behaviour from a Protocol was exactly to promote proper usage with structs.



José Valim
Skype: jv.ptec
Founder and Director of R&D

Chris McCord

unread,
Dec 8, 2016, 11:04:03 AM12/8/16
to elixir-l...@googlegroups.com
I find that importing Access makes the *_in and friends much nicer:


   update_in(foo.bar[id], &(...))
   # vs
   update_in(foo, [key!(:bar), key(id)], &(…))


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/CAGnRm4JsQ_2vMC5tvKJR6K8iePUJB2tPX_7OvxHEQ6TT7hp%2B-g%40mail.gmail.com.

Allen Madsen

unread,
Dec 8, 2016, 11:05:29 AM12/8/16
to elixir-l...@googlegroups.com
Elixir could define Access.keys/1, which would work like the following:

Access.keys([:foo, bar]) == [Access.key(:foo), Access.key(bar)]

For defaults, you would use a tuple of key and default.

Access.keys([{:foo, %{}}, bar]) == [Access.key(:foo, %{}), Access.key(bar)]

Victor Hugo Borja

unread,
Dec 8, 2016, 5:10:12 PM12/8/16
to elixir-l...@googlegroups.com
I implemented a tiny macro on my [Indifferent](http://github.com/vic/indifferent) lib, `Indifferent.path` which just takes the access path and converts it to an "access function" as expected by `Kernel.get_in`, so maybe it could be of any use/inspiration here.



Michał.

--
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+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
vic

Quaerendo invenietis.
Reply all
Reply to author
Forward
0 new messages