Erlang & Elixir DISCUSSION

If Elixir data is immutable, why can I write x = 1 and then x = 2, and why does Erlang reject it?

Started by venkatesh Elixir immutabilityvariable rebindingpin operatorpattern matchingErlang single assignment
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

If Elixir data is immutable, why can I write x = 1 and then x = 2, and why does Erlang reject it?

venkatesh Erlang & Elixir Forum
#1

Tutorials say that data in Elixir is immutable, yet x = 1 followed by x = 2 works and x is then 2. In the Erlang shell, X = 1. followed by X = 2. fails with a "no match of right hand side value" error. Meanwhile my attempt to sum a list with total = 0 and Enum.each(list, fn n -> total = total + n end) leaves total at 0.

What does immutability mean here, and how are these three observations consistent?

Community replies 5

Re: If Elixir data is immutable, why can I write x = 1 and then x = 2, and why does Erlang reject it?

#2

Immutability is about values, not names. A list, map, tuple or binary can never be changed after it is created; functions that seem to modify one return a new value. After list = [1, 2, 3], the call List.delete(list, 2) returns [1, 3] and list is still [1, 2, 3].

x = 2 does not alter the value 1. It rebinds the name x to a different value from that point on. Anything that captured the old value keeps it: x = 1; f = fn -> x end; x = 2; f.() returns 1.

Re: If Elixir data is immutable, why can I write x = 1 and then x = 2, and why does Erlang reject it?

#3

In both languages = is the match operator, not assignment. The left side is a pattern that is matched against the right side, and unbound variables in the pattern get bound. The languages differ in what an already-bound variable means in a pattern. In Erlang it stands for its current value, so the second X = 2 is really the match 1 = 2, which fails. In Elixir a variable on the left is simply bound again.

To get the Erlang behaviour in Elixir, use the pin operator: ^x = 2 with x bound to 1 raises MatchError. It is mostly used inside larger patterns, such as {:ok, ^expected_id} = fetch() or in case clauses that must compare against an existing variable.

Re: If Elixir data is immutable, why can I write x = 1 and then x = 2, and why does Erlang reject it?

#4

The Enum.each example shows that rebinding is local to a scope. The anonymous function has its own scope: total = total + n creates a new total inside the function body, which vanishes when the function returns, and the outer one is untouched (the compiler warns that the inner variable is unused). The same applies to rebinding inside if, case and for blocks.

The functional way is to carry the running value explicitly: Enum.reduce(list, 0, fn n, acc -> acc + n end) returns 6 for [1, 2, 3], or just Enum.sum(list). For a conditional update, use the value of the block: x = if ready?, do: x + 1, else: x.

Re: If Elixir data is immutable, why can I write x = 1 and then x = 2, and why does Erlang reject it?

#5

Immutability is not as expensive as it sounds, because new values share structure with old ones. Prepending with [0 | list] allocates one cell that points at the existing list, a constant-time operation, and updating one key of a large map reuses the unchanged parts. The operations to watch are the ones that must copy: list ++ [item] copies the whole left-hand list, so appending in a loop is quadratic. Prepend and call Enum.reverse/1 once at the end.

Re: If Elixir data is immutable, why can I write x = 1 and then x = 2, and why does Erlang reject it?

#6

State that really has to change over time lives in processes. A process runs a loop that receives a message, computes a new state from the old one and calls itself with it; GenServer and Agent package that pattern. Because no two processes ever share a mutable value, there are no data races to guard against with locks, and a process can be garbage-collected or restarted without affecting the data held by others. ETS tables are available when you need a shared, mutable key-value store with fast concurrent reads.

TEP COMMUNITY