16

Is it possible to have a function for setting values inside an existing struct? I'm talking about the idea of passing the existing struct into a function and setting that structs "name" value (for example)?

What I have:

main.exs

  Code.require_file("user.exs") # Requiring in module

  person1 = User.constructor("Name") # Making a new user

  IO.write inspect person1

user.exs

defmodule User do
  defstruct [name: ""]

  def constructor(name) do
    %User{name: name}
  end
end

Any way to get this idea working?

def setName(struct, newName) do
  struct.name = newName
end

Thanks

1
  • 1
    When you initialize the struct, you should be able to just write it out like you did in your user.exs like person1 = %User{name: "Name"} instead of calling some constructor function. Commented Jan 27, 2016 at 14:40

1 Answer 1

24

Absolutely. There are several ways this can be accomplished.

Method 1

This will error at compile time when trying to set a field missing from the struct

  defmodule User do
    defstruct name: nil
    def set_name(user, name) do
      %{user | name: name}
    end
  end

Method 2

This will silently discard invalid keys

    def set_name(user, name) do
      user |> struct(%{name: name})
    end

Method 3

This will input invalid keys into the struct

    def set_name(user, name) do
      user |> Map.put(:name, name)
    end

Method 4 & 5

These will raise a runtime error when trying to set a field that is not in the struct

    def set_name(user, name) do
      user |> struct!(%{name: name})
    end

    def set_name(user, name) do
      user |> Map.update!(:name, name)
    end
Sign up to request clarification or add additional context in comments.

5 Comments

Note that structs as all Elixir data structures are immutable, so all these actually create a new Struct with all fields having the same values as the old one except for name which is set to the new value.
Thank you. Im coming from OOP stuff so its a bit hard to get used functional stuff. Appreciated.
Also be aware that all of the approaches have subtle differences, especially when setting invalid keys. Method 1 will raise when trying to set a non-existing key (since a struct has all keys it will fail for invalid keys), method 2 will silently discard all invalid keys, method 3 will just set the value and potentially leave you with an invalid struct. So, please don't use Map.put! Finally, another possible method is Map.update!, which is equivalent to method 1.
@molnarpw remember that you can accept an answer if it helped you.
Just a note that the comment from @PatrickOscity is no longer entirely correct. As of Elixir 1.17 Map.update! and %{user | name: name} differ, as the latter is checked at compile time (so generally I prefer it over the other solutions).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.