Serialization Is the Secret

Immutability and Rebinding in Elixir

  • Elixir variables are immutable values with rebinding: assigning x = x + 1 creates 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.