jonnifyelixir
F2 / F2.06 / environment

F2.06 · part 1 of 3

Capturing the environment

A closure captures the value of each variable as it stood when the function was defined — not a live link to the variable. Because Elixir bindings are immutable, that captured value never shifts underneath the function. The environment it carries is a fixed snapshot.

In languages with mutable variables, a closure capturing a loop variable is a classic trap: every closure ends up seeing the final value. Elixir sidesteps this. Rebinding a name creates a new binding; the closure still holds the value it captured. So a closure’s behaviour is settled the moment it is created.

Captured at definition

When a closure is created, it copies the values it needs. Rebind one of those names afterwards and the closure is unaffected — it kept the earlier value. Set the value at capture and the value it is rebound to, and the closure ignores the rebind.

Set both values.

capture by value
the closure stores the value at definition time, not a reference.
lexical scope
a function can see the variables in the block where it was written.
immutability
rebinding a name makes a new binding; the old value still exists.
snapshot
the captured environment is fixed once the closure is created.

rebinding x does not change the closure

1
2
1. x = 1 2. f = fn -> x end # captures 1 3. x = 2 # a new binding 4. f.() => 1 # still the captured value


      
captured x = 1 · rebound to 2 · f.() = 1, not 2

F1.04 · immutability

Because values never mutate, a captured value stays exactly as it was.

Elixir

Rebinding x shadows the old binding; closures over it are untouched.

A closure freezes the values it captures. Later rebindings make new bindings and leave the closure’s snapshot intact.

Several variables at once

A closure can capture more than one variable. make_line captures a slope and an intercept, returning a function of x that computes the line. Both captured values ride along; the returned function needs only x.

Set the captured slope and intercept, then the input.

make_line captures slope and intercept

2
3
4
closure (captures slope, intercept) fn x -> 2 * x + 3 end apply x 11 slope * x + intercept = 2 * 4 + 3 = 11


      
captures slope = 2, intercept = 3 · x = 4 · result 11

Idea

The environment is a snapshot of every captured variable, not only one.

F2.06.3 · currying

Capturing arguments one at a time is how currying is built.

One closure can hold several values. make_line bakes in slope and intercept, leaving a clean function of x.