← back to programming

Multiple Representations

Abelson & Sussman · 1996 · SICP §2.4

The same abstract data can have multiple concrete representations. Tagged data and dispatch tables let representations coexist without knowing about each other. This is the birth of extensibility: adding a new representation requires no changes to existing code.

rectangular polar real-part magnitude car z r cos θ √(x²+y²) car z dispatch table: operations × types → implementations

Representations for complex numbers

A complex number can be stored as rectangular (real, imaginary) or polar (magnitude, angle). Both are valid. The operations real-part, imag-part, magnitude, angle define the abstract interface. Two teams can implement independently.

Scheme

Tagged data

Problem: both representations are just pairs. How does a generic operation know which one it's looking at? Answer: attach a type tag. (attach-tag 'rectangular (cons 3 4)) produces (rectangular 3 . 4). The generic operations dispatch on the tag.

Scheme

Data-directed programming

The conditional dispatch above doesn't scale: adding a new representation means editing every generic operation. Data-directed programming uses a two-dimensional table indexed by (operation, type). Each representation installs its own procedures. The generic operation just looks up the table.

Scheme

Message passing

Instead of a central dispatch table, each object carries its own dispatch. You "send a message" (the operation name) to the object, and it returns the right value. This is what object-oriented programming looks like from first principles: an object is a closure that dispatches on a symbol.

Scheme

Notation reference

Scheme Python Meaning
(attach-tag 'type data)dict(type=..., ...)Tag data with its type
(type-tag datum)datum.get('type')Extract the type tag
(contents datum)datum (minus type key)Extract the payload
(put op type proc)dispatch[(op, type)] = fnInstall in dispatch table
(get op type)dispatch.get((op, type))Look up dispatch table
(apply-generic op datum)apply_generic(op, datum)Dispatch on type tag

Translation notes

The three dispatch strategies — explicit conditional, dispatch table, message passing — correspond directly to patterns in mainstream OOP. Explicit conditionals are isinstance checks. Dispatch tables are the visitor pattern. Message passing is virtual method dispatch. Python classes combine all three: isinstance for ad-hoc checks, __init_subclass__ for registry patterns, and regular methods for message passing.

SICP's insight is that these are all the same mechanism (dispatch on type) organized differently. Data-directed programming is the most extensible: new types and new operations can be added independently. This is exactly the expression problem that haunts every language design.

Neighbors

SICP chapters

  • 🪄 Chapter 6 — Symbolic Data (pattern matching on expression types)
  • 🪄 Chapter 8 — Generic Operations (extending dispatch to arithmetic across types)

Foundations (Wikipedia)

Ready for the real thing? Read SICP §2.4.