Commissioned for this museum · after Gamma, Helm, Johnson & Vlissides, 1994

Visitor

TypeScript·1994·38 lines·1205 bytes

Curator’s note

This is the pattern people find hardest to love, and it answers a genuinely awkward question: your data has a fixed set of shapes and you keep needing new operations over them. Put each operation on the shapes as a method and every new operation edits every shape. Visitor turns that inside out — the shapes stay closed, and each operation becomes one object holding all the cases.

The trade is not free and deserves to be said plainly. Visitor makes adding an *operation* cheap and adding a *shape* expensive: define a fourth kind of node and every visitor stops compiling. Methods on the shapes make exactly the opposite trade. Neither is correct in general — they are opposing bets about which axis will grow, and betting wrong is why people come to resent this one.

The Visitor<T> mapped type is doing what the 1994 version needed an abstract class and a double-dispatch dance to achieve. It says: one handler per kind, exhaustively, and the compiler will hold you to it. In a language with unions that exhaustiveness is the entire reason to reach for this.

node as never is the one wart, and it is left visible on purpose. At that point walk knows visitor[node.kind] is *some* handler and node is *some* node, but not that the two agree — a fact that is true and that the type system cannot yet follow. Every real implementation has this wrinkle somewhere; hiding it behind an overload would make the exhibit less honest, not less awkward.