Hero image for "Ada Didn't Invent Safety. It Made Safety Non-Negotiable."

Ada Didn't Invent Safety. It Made Safety Non-Negotiable.


Lesson 11: What a 1970s Government Contract Teaches About Modern Language Design


The United States Department of Defense surveyed its own software in the early 1970s and found something alarming. Not a security vulnerability, not a performance bottleneck — a census problem. Over 450 distinct programming languages and dialects were running across its weapons systems, logistics infrastructure, and command-and-control apparatus. Nobody could audit it. Nobody could maintain it across programs. The DoD had accidentally built the world's most expensive Tower of Babel.

The response was Ada — a language designed not by a startup chasing elegance, but by a government procurement process chasing control. That origin story matters, because it explains why Ada made choices that the rest of the industry spent decades calling excessive, and is now spending decades trying to replicate.


The Problem Ada Was Actually Solving

Ada wasn't designed to be expressive or concise. It was designed to be legible to strangers under adversarial conditions — the conditions of long-lived government software, where the original authors are gone, the requirements have changed, and a bug in the flight control system costs lives rather than uptime.

That constraint produced a specific philosophy: the compiler enforces legality, visibility, typing, and safety checking that most languages leave to convention or tooling. Ambiguity is treated as an error. The programmer must name what they mean.

Concretely, this meant Ada shipped with features that seemed academic in 1983 and look prescient now:

  • Range-constrained types. You don't declare an integer; you declare a Day_Of_Month that can only hold values 1–31. The type carries its own validity contract.
  • Built-in concurrency. Ada's tasking model is part of the language specification, not a library you bolt on. Go would arrive at a similar model independently, thirty years later.
  • Protected objects. Safe shared state without raw mutexes — the compiler enforces the discipline.
  • Contract-based programming. Preconditions, postconditions, and type invariants as first-class language features. Ada 2022 includes these natively.

The industry called this verbose. What it actually was: explicit. Ada forced you to state your assumptions so the compiler could check them.


What Modern Languages Quietly Borrowed

Here's the uncomfortable part of Ada's history: the features that made it seem bureaucratic are exactly what Rust, Elm, and F# now market as selling points.

Rust's ownership model is a novel mechanism, but the goal — eliminating a class of bugs at compile time rather than catching them at runtime — is Ada's founding premise. Rust spent a decade converging toward Ada's safety guarantees from one direction, arriving via borrow checking where Ada arrived via strong typing and range constraints. Different routes, same destination.

The SPARK subset of Ada pushes this further. SPARK is a formally verifiable subset of Ada — code that can be mathematically proven correct, not just tested. It prohibits side effects in expressions and aliasing of names, restrictions that feel severe until you realize they're what make automated proof tractable. This is the direction Rust's type system gestures toward; SPARK has been doing it in production avionics for years.

The pattern repeats with generics. Ada made generics a first-class, standardized feature of a widely deployed systems language before C++ templates existed in their modern form. The idea that a type system should catch parametric errors at compile time — not at instantiation, not at runtime — is now table stakes. Ada was the first language to treat it as non-negotiable.


The Lesson: Safety as Architecture, Not Afterthought

The reason Ada's influence is invisible is that it worked through osmosis rather than adoption. Nobody migrated their startup to Ada. But the designers of Rust, Go, and Elm were solving the same problems Ada solved, and they arrived at similar answers — because the problems have correct answers.

S. Tucker Taft of AdaCore, writing about Go, Rust, and parallel systems programming, framed it plainly: all three languages were trying to help programmers address new architectures without letting complexity exceed what a human programmer can manage. That's Ada's original brief, restated for multicore hardware.

The design lesson isn't "use Ada." It's that safety features aren't a tax on productivity — they're a form of documentation that the compiler can enforce. Every time you write a Rust lifetime annotation or an Elm type alias that encodes business rules, you're doing what Ada programmers were required to do in 1983. The compiler is your co-author, not your adversary.


Next action: Pick one place in a current codebase where a raw integer or string is carrying implicit constraints — a user ID that must be positive, a percentage that must be 0–100 — and model what an Ada-style range type would look like there. You don't need Ada to apply the thinking. The question is: what does your type system currently allow that your domain forbids?