grantwest
Concise nil safe way to access field on nested struct?
If I have nested structures, and I want to fetch a field from the a nested structure, but handle a nil case, is there a succinct way to do that? Lets say I have a Project struct which has a client field, which is itself a struct that has field name:
project = %Project{}
name = project.client.name
This works, but if client is nil we get an error. If these were maps I could do
name = get_in(project, [:client, :name]) || ""
Now we get the name if it exists, or we have an empty string. This does not work with structs because they don’t implement access. Is there a similarly concise solution for structs?
Most Liked
kevinschweikert
In Elixir 1.17 you can use get_in/1 like this get_in(struct.foo.bar)
Docs: Kernel — Elixir v1.17.0-rc.1
In case any of the keys returns
nil, thennilwill be returned andget_in/1won’t traverse any further.
benwilson512
It may be heretical but for all of my ecto structs at least we just went ahead and implemented the Access behavior functions so that we can just use access normally. The ergonomics are really nice.
benwilson512
Yeah I think that moduledoc is perhaps a bit too strongly worded, because it isn’t that structs aren’t allowed to use that syntax, it’s just that it won’t work by default.
Not really, it’s worked great. In fact in particular, it works rather well with how Ecto handles associations that aren’t loaded yet. Eg:
shipment.origin_location[:customer][:name]
If you forget to Repo.preload(shipment, [origin_location: :customer]) then you get:
** (UndefinedFunctionError) function Ecto.Association.NotLoaded.fetch/2 is undefined (Ecto.Association.NotLoaded does not implement the Access behaviour.
Which is great! You didn’t load the association and so instead of treating that as just nil it errors, indicating that you need to actually load it to determine if it’s there or not.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex










