Skip to main content
computer-science

Make wrong unrepresentable

Description

Replace a conditional runtime gate with a structural absence: instead of checking-and-rejecting an invalid state on each request, ensure the invalid state has no representation in the system’s construction at all. The handler doesn’t exist for the invalid path; the component doesn’t expose the invalid action; the type can’t hold the invalid value. The invariant is enforced by the topology of what’s constructible, not by predicates evaluated at runtime. The structural shape: where an active-gate checks if (condition) reject, make-wrong-unrepresentable removes the code path entirely — there is no if to forget, no bypass to find, no flag to flip. The invalid state is literally absent from the state space rather than blocked at entry. This produces three advantages: the invariant can’t be accidentally bypassed, the check doesn’t need to be maintained across codebase evolution, and the resulting system’s surface is smaller (fewer exposed handles for invalid operations). This is the hardest version of active-gate — not “gate on validation” but “remove the gate’s target domain from the system’s representable space.” The gate becomes structural rather than behavioral.

Triggers

User-initiated: User is discussing validation, invariants, or error cases — especially when the current approach is a runtime check that “should” prevent an invalid state. Also when user expresses a desire for “stronger” guarantees than the current check provides. Agent-initiated: Engine detects a runtime gate pattern (check-and-reject) and evaluates whether the structural-absence alternative is available. Candidate inference: “this runtime gate is a candidate for make-wrong-unrepresentable — can the invalid state be excluded from the system’s representable space, so the check becomes unnecessary?” Vocabulary cues: “make the wrong thing unrepresentable,” “illegal states,” “invalid state,” “structural invariant,” “encode in the type,” “handler doesn’t exist,” “literally can’t,” “harder to bypass,” “can’t be bypassed,” “remove the handler,” “structural enforcement,” “type-safe.” Situation-shape signals: A runtime check or validation that fires on every request to block a specific invalid state. The concept is indicated when the invalid state could be excluded from the construction space rather than blocked at each access. Strongest signal: if removing the check would require actively adding invalid-path code, the absence is already structural.

Exclusions

  • Transiently invalid states during construction — partial-builder patterns require states that are temporarily invalid during construction (a half-built object). Structural enforcement is too tight; runtime checks must take over during the construction phase.
  • Invariants that require global facts — some invariants can’t be made structural because they depend on facts only knowable at runtime (e.g., “no duplicate usernames” requires knowing all existing usernames). No local type can enforce this.
  • When the constraint is too tight — if the invalid state is needed in some contexts (e.g., testing, admin paths), making it unrepresentable forecloses legitimate uses. The concept requires that the invalid state be truly invalid across all contexts.
  • In dynamic or interpreted contexts — some languages/frameworks don’t support structural enforcement at the level needed (e.g., purely dynamic schemas). Runtime gates may be the only practical option.

Structure

Internal structure of make-wrong-unrepresentable: a table of its component slots and the concepts that fill them. Shape: the right structural design makes invalid states unrepresentable — it’s a shape question, not a logic question. Asymmetric-gate: the asymmetry is now absolute (invalid path doesn’t exist vs. valid path does); the cost asymmetry is maximal. Load-bearing: the absence of the handler is load-bearing — removing the handler would require adding it back, which would be the architectural regression.

Relationships

Relationship neighborhood of make-wrong-unrepresentable: a graph of the concepts it connects to and the concepts it is a part of.
  • shapecreation relationship — the structural design that makes invalid states unrepresentable is a shape question: what topology forecloses the invalid path? Make-wrong-unrepresentable is a specific application of the shape primitive.
  • asymmetric-gatespecialization relationship — the extreme case of asymmetric-gate where the asymmetry is binary (invalid path doesn’t exist) rather than graded (invalid path costs more). The active-gate concept reduces to make-wrong-unrepresentable when the cost of the invalid path can be made infinite (by removing it).
  • active-gate-vs-passive-auditspecialization relationship — make-wrong-unrepresentable is the most aggressive gate posture: not just “block at entry” but “remove the entry.” The concept sits at the gate-maximalist end of the gate/audit spectrum.
  • graduation-promotioncreation relationship — systems often evolve from runtime checks → active gates → make-wrong-unrepresentable as understanding of invariants matures. The graduation move produces structural enforcement as its mature form.
  • load-bearingcomposition relationship — the absent handler is load-bearing by its absence; removing it (adding the handler back) would be the architectural regression. Identifying which absences are load-bearing is the diagnostic move.

Examples

Type-system encoding of business rules · computer-science

a NonEmptyList type vs. List with a runtime “must not be empty” check. The type makes the empty case unrepresentable at the point of construction; the check can be forgotten, the type cannot.

Route-level access control · computer-science

a route that doesn’t exist for unauthorized users (not routed to) vs. a route that checks authorization at entry. The former makes the unauthorized access path unrepresentable; the latter just blocks it.
a finite state machine that doesn’t include an “invalid” state as a valid transition target; invalid transitions are not implemented rather than checked-and-rejected. Moving from if (transition.isValid()) to “invalid transitions don’t exist in the state table.”
UI component work: no onMouseDown on filled cells = literally can’t start a drag on an invalid target. The piece-on-cell component doesn’t expose the drag-initiation surface rather than exposing it and gating with if (cell.hasPiece) return. Stronger: harder to bypass, cleaner to read.
ReadonlyArray<T> in TypeScript vs. “don’t mutate this array” convention. The type makes mutation unrepresentable; the convention is a runtime gate waiting to be bypassed.
Wlaschin’s Domain Modeling Made Functional is the book-length, domain-driven-design treatment of making wrong states unrepresentable. Its central thesis is that the type system is a design tool, not just a bug-catcher: model the domain so precisely with types that the compiler refuses to build any program capable of entering an illegal state. The vehicles are F#‘s algebraic data types — records (product / “AND” types) for data that belongs together, and discriminated unions (sum / “OR” types) for states that are mutually exclusive — plus single-case wrappers (type CustomerId = CustomerId of int) that defeat “primitive obsession” by making a CustomerId un-substitutable for an OrderId or a raw int.The move that most directly instantiates the concept is encoding an invariant into the type rather than checking it. Instead of an EmailAddress string plus an IsVerified boolean — which permits the illegal combination “verified-but-no-address” or lets the flag drift out of sync — Wlaschin models EmailContactInfo = Unverified of EmailAddress | Verified of VerifiedEmail, so that a function requiring a verified email can only be called with the Verified case. The unverified-but-treated-as-verified state is not blocked at runtime; it has no representation to block.Inference: The discipline Wlaschin codifies is “parse, don’t validate at every use” applied through the type system — push each invariant into the shape of the data at its construction point, so downstream code receives a value that is correct-by-construction and the compiler enforces it exhaustively. The diagnostic for whether you have actually made wrong unrepresentable (versus merely guarded): can you write down a value of the type that violates the rule? If you still can — a bool that could disagree with a string, an int that could be negative where only positives are legal — you have a runtime gate, not structural absence, and someone will eventually slip past it.
The slogan this concept is named against — “make illegal states unrepresentable” — was coined and popularized by Yaron Minsky of Jane Street, in his 2010 “Effective ML” talk and the accompanying blog post (it was Item 3). The principle: design your data types, using variant (sum) types, so that invalid combinations of data simply cannot be written down in the language, moving error-checking from runtime to compile time. Minsky’s canonical illustration is a network connection. The naive model is one record with server, session_id, and last_ping fields, made optional to cover the disconnected case — but optionality permits the illegal state “disconnected, yet holding a session_id.” The fix is a variant where each state carries exactly the data it should:type connection_state = Disconnected | Connecting of \{...\} | Connected of \{session_id; last_ping\}Now a session_id only exists inside the Connected case; there is no way to construct a disconnected connection that has one. The compiler’s exhaustiveness checking adds the second half: every place that consumes a connection_state is forced to handle every legal case, so a newly added state cannot be silently ignored.Inference: Minsky’s framing is why the catalog prefers “make-wrong-unrepresentable” over a property-name like “unrepresentable-invariant” — it names the move, the active design decision to delete the illegal state from the space of constructable values rather than to guard against it. The diagnostic is the same one the connection example dramatizes: look for a boolean-plus-data or optional-field encoding where two fields could contradict each other (a flag that disagrees with the payload, an option that’s Some when the state says it should be None). Each such pair is a representable illegal state — a runtime check waiting to be forgotten — and the remedy is to re-shape the type as a variant so the contradiction has nowhere to live.