Serialization Is the Secret
Immutability and Rebinding in Elixir
- Elixir variables are immutable values with rebinding: assigning
x = x + 1creates a new value and binding, old references don’t change. - Some see rebinding and in-place mutation as equivalent at the mental model level; others stress a key guarantee: a function’s local variable cannot be changed “behind your back” by other code.
- Process dictionaries and message passing are cited as the main ways state actually changes; observing mutation always goes through explicit function calls or receives.
Comparison with Haskell, SSA, and Other Paradigms
- Haskell’s immutability is stricter: bindings can’t be reassigned; shadowing creates new scopes. Mutable references (e.g., IORef, State monad) exist but are explicit.
- Lazy infinite data structures are discussed: Haskell’s infinite lists vs Elixir’s
Stream/Stream.unfold. Elixir supports similar patterns but less pervasively and less elegantly. - Some note that compiler IRs like SSA also treat assignments as new bindings, but that doesn’t make C/C++ “immutable” at the language level.
Actor Model, Concurrency, and Serialization
- GenServers/processes are described as owning state and serializing all mutations through a mailbox, avoiding shared-memory races.
- This model is praised for predictable concurrency and local reasoning, but some find it cognitively heavier and less intuitive than mainstream mutable models.
- Comparisons are made to JS’s single-threaded event loop: serialization within handlers simplifies reasoning, though true parallelism still needs extra constructs.
- Rust and Clojure are cited as examples of “structured mutability” (ownership, atoms, etc.) that control who can mutate and when, without full immutability.
Referential Transparency and Reasoning
- Rebinding within the same scope can break simple equational reasoning; you must scan all prior lines for reassignments.
- Others argue it’s syntactically equivalent to nested
let-blocks and can still support clear reasoning if used sparingly.
Performance and Memory Concerns
- Questions are raised about constant allocation and copying in immutable systems.
- Responses point to structural sharing, GC, compiler optimizations, and the fact that apparent copies may be optimized out.
- Elixir/Erlang are not the fastest for raw computation but shine under high concurrency; Phoenix’s microsecond-level latencies are given as anecdotal evidence.