Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using `|` when instantiating a new struct

Tags:

elixir

The following code is copy-pasted from 'Elixir in Action' published by Manning.

defmodule TodoList do

  defstruct auto_id: 1, entries: HashDict.new

  def new, do: %TodoList{}

  def add(
    %TodoList{entries: entries, auto_id: auto_id} = todo_list,
    entry) do
      entry = Map.put(entry, :id, auto_id)
      new_entries = HashDict.put(entries, auto_id, entry)
      %TodoList{ todo_list |
        entries: new_entries,
        auto_id: auto_id + 1
      }
    end

end

I do not understand the use of todo_list | at the end of the add function when creating the new TodoList. I tried removing it altogether and couldn't really see a difference in the result. Can anyone explain to me what it is achieving?

like image 726
vptheron Avatar asked Feb 09 '23 17:02

vptheron


1 Answers

This is shorthand syntax for updating a map:

iex> map = %{foo: "bar"}
%{foo: "bar"}

iex> map = %{map | foo: "quux"}
%{foo: "quux"}

Note that unlike Map.put/3, you can only update existing keys, which gives you some safety. It behaves more like Erlang's :maps.update/3.

iex> map = %{map | baz: "quux"}
** (ArgumentError) argument error
    (stdlib) :maps.update(:baz, "quux", %{foo: "bar"})
    (stdlib) erl_eval.erl:255: anonymous fn/2 in :erl_eval.expr/5
    (stdlib) lists.erl:1261: :lists.foldl/3

Also note that structs like your %TodoList{} are really just maps, so all of this works exactly the same way with structs.

Now, because you are setting all valid keys of the struct it makes no difference whether you put the todo_list | in there or not for now. However, if a new key is added to the struct, your add function might not work as expected any more, discarding the other keys. So I'd recommend you leave it in there.

like image 126
Patrick Oscity Avatar answered Feb 24 '23 22:02

Patrick Oscity