Pranoy Dutta’s short essay is three language features with a minimal code sample each: Crystal’s flow typing, Rust’s borrow checker, and contract programming in D. The thread connecting them is placement — the check lives where the invariant does, declared once and enforced by the compiler or runtime, instead of being restated in every caller and re-verified in review.

Flow typing. In Crystal a variable can change type over its lifetime, and the compiler tracks the type at each program point:

  • Before a branch my_var is Int32; inside it, String; afterwards, Int32 | String — the union is what the compiler reports when it “cannot actually guarantee one or the other.”
  • Calling a String method on that union is a compile error until you add is_a?(String), which narrows the type. The check is demanded only where it’s genuinely unknowable.
  • Static checking that feels dynamic, with no meaningful runtime cost. TypeScript’s control-flow narrowing is the same idea.

Borrow checking. Rust’s rules are short: a borrow can’t outlive its owner, and you get exactly one mutable reference (&mut T) or any number of immutable ones — never both.

  • That’s a readers-writer lock as a compile-time property. Data races only require synchronizing reads against writes, so serializing writes to a location is precisely the invariant that removes them.
  • Nothing at runtime. The cost is compile-time complexity, which Dutta argues is inherent to the subject matter rather than imposed by the language.

Contract programming. D splits two things most languages blur:

  • assert — a violated program invariant, meaning a bug in the program.
  • enforce — an external condition (bad input, environment) that throws.
  • Functions take in { } preconditions and out (result) { } postconditions; classes take an invariant() { } block checked around members.
  • In his BankAccount example, balance >= 0 is declared once at class level instead of re-checked at the top and bottom of every method. daysInFebruary asserts its result is 28 or 29 — anything else is a logical error.

The portable idea is the assert / enforce distinction: naming “this is impossible” separately from “the world misbehaved” changes how a stack trace gets triaged. The second is that invariants declared next to the field they constrain — and checked by the platform — are cheaper than the equivalent discipline maintained in review. Dutta is honest about the trade: borrow checking costs ergonomics, and flow typing’s unions show up in your error messages.