Elixir basics · Lesson 05 (open contents)
Make the shapes match
Treat `=` as a match and unpack tuples, lists, and maps.
Unpack three kinds of collections
Read the shape on the left first. Then find each matching value on the right.
# Save the tag we expect
expected_tag = :ok
# ^ checks the old expected_tag value; _ ignores the third value
{^expected_tag, score, _} = {:ok, 92, :midterm}
# Split the first item from the rest of a list
[first | rest] = ["peach", "plum", "apricot"]
# A map pattern names only the key we need
%{name: name} = %{name: "Robin", age: 12}
{score, first, rest, name}scorebecomes92.firstbecomes"peach", andrestbecomes["plum", "apricot"].namebecomes"Robin".
Read from the first line down
^expected_tagdoes not bind the name again. It requires the tuple's first item to equal the existing:ok;_ignores the third value.[first | rest]matches only a non-empty list. The bar separates the first item from the remaining list.- A map pattern can name only the keys it needs. The extra
agekey does not stop this match.
Symbols are not secret signs
=Match the two sides. New names on the left bind to the matching values.
_The value in this position does not need to be saved.
[head | tail]Split a non-empty list into its first item and the remaining items.
^nameCheck this position against the value already stored in name. Read it as pin name.
Match each name to its meaning
pattern
A shape on the left that checks and unpacks the data on the right.
destructuring
Taking several values out of a collection at once.
match failure
When the shapes or fixed values do not line up, Elixir raises a MatchError.
pin operator
^name uses the value already bound to name instead of binding a new value in that position.
Why these forms are useful
In Elixir, = does more than assign a value. It checks whether the shapes on both sides can match.
The left side is like a form with empty spaces. The data on the right fills them. If a position, label, or key does not fit, the match fails.
This is often used to unpack data. Write only the parts you need. An underscore _ can take the rest.
A plain name in a pattern receives a value. To check against a value that name already holds, add the pin operator ^. ^expected_tag means “this position must equal the old value of expected_tag.”
Why this shape?
Why is = more than assignment here?
A pattern checks a shape and extracts its data in one move. The same idea works at function boundaries, in case, and in receive.
The rules differ across a new match: Elixir rebinds a plain name and needs ^name to check the old value; an Erlang variable becomes a check after its first binding.
Coming from Java, Python, or JavaScript
Java
- Familiar starting point
- Assign a local variable, then inspect an object with accessors or instanceof.
- What BEAM changes
- A pattern checks and unpacks tuples, lists, or maps directly.
- False friend
- This is not method overloading, and it does not mutate the value.
Python
- Familiar starting point
- Unpacking and match/case offer a familiar starting point.
- What BEAM changes
- Data is not changed in place, and patterns are routine tools for function clauses and message protocols.
- False friend
- Elixir can rebind a name without mutating its old value; a bound Erlang variable checks the next match.
JavaScript
- Familiar starting point
- Array and object destructuring mainly extract values.
- What BEAM changes
- BEAM patterns can also require fixed tags; a mismatch selects another clause or fails.
- False friend
- JavaScript destructuring defaults follow different rules.
Close the answer and try
Bind the expected tag, then check it while unpacking the city and temperature from {:weather, "York", 28}.
# Accept only a weather message
expected_tag = :weather
# Pin the old tag and name the other two positions
{^____, ____, ____} = {:weather, "York", 28}
# Return the city and temperature
{city, temperature}Target result: The result should be {"York", 28}.
Stuck? Read one hint
Put ^expected_tag first, followed by city and temperature.
After you run it, see one answer
# Save the tag we plan to check
expected_tag = :weather
# ^expected_tag must match; two new names receive the data
{^expected_tag, city, temperature} = {:weather, "York", 28}
# Look at the values we unpacked
{city, temperature}Think about it: Will `{:ok, value} = {:error, 3}` succeed?
No. The left side requires :ok, but the right side begins with :error, so Elixir raises a MatchError.
Remember these three lines
- 1
=checks a shape. It does not only put a value into a name. - 2
Fixed values check the data. New names receive it.
- 3
Use
^nameto check an old value and_for a value you do not need.