Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum.
In the (beta version of the) book, they update structs using Map.put/3. I’ve found myself doing the same in my own code. @hubertlepicki astutely observed that this opens up the opportunity for mistyped field names when updating your structs: This is totally allowed, the result of Map.put/3 will then be a map (instead of an instance of your struct).
Example:
iex> defmodule Foo do
iex> defstruct bar: 1 , baz: 2
iex> end
iex> foo = %Foo{}
iex> foo |> Map.put(:qux, 4)
%{__struct__: Foo, bar: 1, baz: 2, qux: 4} # <- note that it is printed as a map.
The other two methods known to me to update structs are:
- The special struct update syntax,
%Foo{oldfoo | bar: 4}. This will result in a compile-time error when wrong field names are used. Drawback: It cannot be piped. put_in/2:newfoo = put_in(foo.bar, 4). This will also result in a compile-time error when a wrong field name is used. Drawback: It, too, cannot be piped.
put_in/3 (as in: newfoo = put_in(foo, [:bar], 4) would be able to be piped, but it is not available for structs; it only works on things that implement the Access protocol.
So what is the best way to update structs in practice? Am I missing any method in this list? Would it be a good idea to have a version of put_in that works on structs and is pipeable?
Trending in Questions
Other Trending 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
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex











Showing Posts 1 to 10- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
NobbZ
The special Form
%name{}pipes pretty well I think, you need to wrap in an anonymous funtion though):hubertlepicki
Yes, I raised the issue because I did waste some time on a stupid typo. Generally when I use struct, I want to have only defined fields. Otherwise I’d go with a Map.
But if you do use Map.put/3 on a struct, it works, yet not properly since I mistyped/used wrong key.
I agree that not being able to do it in pipe is not ideal. I found myself wrapping the update syntax in a tiny function/anonymous or othwerwise that does that for the very reason. I don’t know, maybe there is better way somehow so I’m listening too.
hubertlepicki
My eyes hurt. I do the same, but I die a bit every time I have to write it.
NobbZ
In this post it was just for demonstrational purpose, usually I do it in a
def(p)-ed function.michalmuskala
Erlang has
:maps.update/3, which is basically the%{x | key => value}syntax as a function. I think having something similar in elixir would be beneficial. The biggest problem is the name.hubertlepicki
How about something obvious like:
Struct.update/3orStruct.put/3wmnnd
You could also use
Map.update!/3which will pipe nicely and raise if the given key doesn’t exist, though not at compile-time.michalmuskala
We don’t have a
Structmodule - having it for just one-two functions feels wired.hubertlepicki
I can accept @wmnnd’s solution of using
Map.update!/3however.michalmuskala
Yes,
Map.update!is fine - if only you didn’t have to create a useless anonymous function. It’s awesome in many cases thatMap.update!accepts a function, but not for this case.