ELIXIR / CHAPTER 06
Structs and explicit domain shape
IntermediateUse a named data shape without mistaking it for runtime validation.
By the end of this chapter
- Define a struct with known fields
- Distinguish construction requirements from value validation
- Update a struct while preserving its type
The idea
A struct is a map with a named type and a defined set of fields. It documents a domain shape and supports pattern matching on that type. Default values make construction convenient, while @enforce_keys requires selected keys at supported construction points. Requiring a key does not prove that its value has the correct type, range, or meaning.
Keep validation in a constructor function when callers need a trustworthy record. A struct update can require known fields, but generic map operations may produce values that no longer obey the intended struct interface. Prefer operations that retain the struct’s known shape and use pattern matching to distinguish it from an arbitrary map. Immutable updates create new values without modifying existing references.
defmodule TicketRecord do
@enforce_keys [:id]
defstruct [:id, priority: 0]
def demo do
original = %__MODULE__{id: "t1", priority: 2}
updated = %{original | priority: 5}
{original.priority, updated.priority}
end
end
IO.inspect(TicketRecord.demo()){2, 5}The updated struct is a new value. The original retains priority two, and the known field is changed explicitly.
Try it yourself
Write a constructor returning {:ok, struct} only for a nonempty id and nonnegative priority.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING