← the guideObjects Ascendant

§ 02 — Eras · 1986

Erlang

nine nines, designed into the grammar

Left: era context, features, and the 101 hello. Right: 3 core concepts, 3 deeper 201 lessons, the factorial specimen, and where Erlang lives today — each column scrolls on its own.

creators
Joe Armstrong, Robert Virding & Mike Williams, Ericsson, 1986
status
alive (niche) · telecom, WhatsApp, Discord, RabbitMQ

The problem it solves

Telephone switches must never go down. Erlang made concurrency, distribution and fault-tolerance primitives of the language.

The problem it carries

Numerically slow, syntactically alien, and a hiring pool the size of its home town — brilliant for the nine-nines niche.

Key features

pattern-matching clauses
Each clause is one case; unmatched input is an error rather than a surprise.
processes and messages
Millions of isolated processes that communicate only by sending each other terms.
immutability
No shared mutable state, so data races are designed out rather than debugged.
supervision
Crashes are expected: a supervisor restarts a clean copy, and the fault never spreads.

101 — hello, world

Session one is the smallest program that still counts as speaking Erlang: what every tutorial prints first, in the dialect that mattered when the language arrived (1986).

the first program1986
io:format("Hello, world~n").

101First contact — hello world and 3 ideas that define how Erlang reads. 201 — 3 lessons on mechanisms you meet after the factorial specimen: the sharp edges practitioners actually use.

101 — core concepts

3 fragments, each naming a habit of mind in Erlang. Read the note, then the code — together they are the 101 in one sitting.

01 — pattern-matching functions

Each clause is one case; the mailbox receive is the heart of every process.

loop() ->
  receive
    {ping, From} -> From ! pong, loop();
    stop         -> ok
  end.

02 — processes & messages

Millions of tiny processes, no shared memory, messages only — failure is isolation.

Pid = spawn(fun loop/0),
Pid ! {ping, self()},
receive pong -> ok end.

03 — let it crash

Don’t code defensively: crash, and let the supervisor restart a clean copy.

supervisor(one_for_one,
  [{ship, {ship, start_link, []},
    permanent, 5000, worker, [ship]}]).

201 — going deeper

The 201 assumes you have read the 101 and the specimen. Each lesson is one mechanism — what it is for, how it looks in code, and the trap or payoff that makes Erlang distinctive at scale.

  1. OTP behaviours
  2. ETS and state
  3. dialyzer and specs

OTP behaviours

A behaviour is a callback contract; gen_server, gen_event and supervisors build on it, so the shape of a process is a convention everyone can read.

-callback init(Args :: term()) -> {ok, State :: term()}
              | {error, Reason :: term()}.

ETS and state

ETS tables hold state outside the process heap: fast, shared, and the reason hot code reload works without losing data.

ets:new(crew, [named_table, set, {read_concurrency, true}]),
ets:insert(crew, {perch, 24}).

dialyzer and specs

Specs describe types for the dialyzer, which proves properties across a whole system — the closest Erlang comes to static checking.

-spec tons(ship()) -> non_neg_integer().
tons(#ship{tons = T}) -> T.

The specimen — factorial

The mailbox: every process owns one, messages are the only shared thing, crashes are isolated and supervised — nine nines, designed into the grammar.

the mailbox1986
loop() ->
  receive
    {ping, From} -> From ! pong, loop();
    stop         -> ok
  end.

Run it today

installbrew install erlang

runescript fact.erl

Where it is now

WhatsApp ran hundreds of millions of users per Erlang node; Discord and RabbitMQ still do.