◄ WORLD V · SONNY 5DART 260 · a helldive at the net

THE PHANTOM TYPE a type parameter with no runtime value — a tag the compiler enforces, then erases

A phantom type is a type parameter that appears in the type but not in the data: Length<Meters> and Length<Feet> are both just a number at runtime, but the compiler treats them as different types and refuses to add them. You get unit safety (no Mars-Climate-Orbiter mix-up), validated-vs-raw string distinctions, and state-machine typestate — all enforced at compile time and erased to nothing at runtime. The tag rides in the type, costs zero bytes, and vanishes before execution. Safety you do not pay for.

THE TECHNIQUE a type-only tag: distinct types, identical runtime representation

Length<Meters> and Length<Feet> are the same number at runtime. The demo shows the tag is erased — identical representation — while the type would forbid mixing: live demo


HISTORY & CREDIT Leijen-Meijer 1999 · Cheney-Hinze 2003

“A type that carries no data does nothing.” — it does the checking, then disappears. The phantom parameter is invisible at runtime and decisive at compile time: it makes meters + feet a type error and costs not one byte. cited

1999 · Daan Leijen & Erik Meijer — phantom types to embed a typed query language (domain tags in the type).
2003 · James Cheney & Ralf Hinze — a systematic account of phantom types.
now · units-of-measure (F#), typestate, validated newtypes, Rust PhantomData.

The tag lives only in the type, so it constrains the program and then costs nothing to run. Compile-time distinction, runtime erasure — the cleanest “safety you do not pay for.” Cheney-Hinze 2003

RECOMMEND FOR I-13 the phantom tag is erased, computed

On the canonical compiler, Length<Meters> 100 and Length<Feet> 100 have identical runtime representation — their difference is 0, the tag having vanished:

$ i13 run t_phantom.i13 # meters and feet: same runtime rep meters = 100 feet = 100 same_runtime = 0 -- the phantom tag is erased; only a typed compiler could tell them apart
Recommend: the phantom type is the whole batch in miniature. At runtime i13 and a phantom-typed language are identical — the tag is erased, both just hold 100 (the demo's same_runtime = 0 proves it). The only difference is the compile-time check a typed language runs and i13 does not: forbidding meters + feet. That is exactly what types: NOT COVERED means — i13 keeps the zero-cost runtime and forgoes the zero-cost safety. Phantom types are proof that the thing i13 declines costs nothing to run; it only costs a checker.