Qqwy

Qqwy

TypeCheck Core Team

Updating structs: Map.put vs %Foo{oldfoo | new: value} vs put_in

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:

  1. 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.
  2. 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?

Most Liked

hubertlepicki

hubertlepicki

My eyes hurt. I do the same, but I die a bit every time I have to write it.

14
Post #4
NobbZ

NobbZ

The special Form %name{} pipes pretty well I think, you need to wrap in an anonymous funtion though):

iex(1)> defmodule S do
...(1)>   defstruct f: 0
...(1)> end
{:module, S, <<...>>, %S{f: 0}}
iex(2)> s = %S{}
%S{f: 0}
iex(3)> 1 |> (&%S{s | f: &1}).()
%S{f: 1}
iex(4)> s |> (&%S{&1 | f: &1.f + 5}).()
%S{f: 5}
11
Post #2
josevalim

josevalim

Creator of Elixir

@michalmuskala I always thought about put_existing and put_existing! (which neatly mirrors put_new).

michalmuskala

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.

josevalim

josevalim

Creator of Elixir

Please send a PR. Probably put_new!, put_existing and put_existing!.

Where Next?

Popular in Questions Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement