Type Systems & Memory

The Contracts Beneath the Code

This appendix digs into the deeper mechanical differences between programming languages, the ones Chapter 11 only touched on in passing. Knowing how they work helps explain why different languages make the trade-offs they do.

Type Systems: Contracts in Code

Consider a simple function:

function add(a, b) {
  return a + b;
}

What can you pass to this function? In JavaScript, almost anything. Two numbers? Sure. Two strings? Absolutely, it concatenates them. A number and a string? JavaScript doesn’t even complain: add(5, "3") quietly stringifies the 5 and hands back "53", not 8. No error, no crash, just a wrong-looking answer waiting to cause trouble three functions downstream.

JavaScript uses dynamic typing: types are barely checked at all, and what little checking happens occurs at runtime, when the code actually executes and it’s often too late to matter.

Now consider Go:

func add(a int, b int) int {
    return a + b
}

This function accepts two integers and returns an integer. That’s not a suggestion; it’s a contract enforced before the code ever runs. This is static typing. Try to pass a string here and the compiler will refuse to compile your code. No running, no runtime error, just a stern message that you’ve violated the contract.

JavaScript itself has no such contract, but TypeScript layers exactly this kind of enforcement on top of it:

function add(a: number, b: number): number {
  return a + b;
}

Annotate the parameters and the return type, and the same guarantee Go builds into its compiler, TypeScript builds into yours. Call add("5", 3) here and the TypeScript compiler stops you before the code ever runs, no waiting for a quietly wrong answer to surface downstream.

Neither approach is universally better. They’re trade-offs.

Explore the static-to-dynamic typing continuum.

Memory Models: Who Cleans Up?

Every program uses memory. The interesting question is who cleans it up when you’re done, because the dishes don’t wash themselves.

Click each model to see how different languages handle memory.

Domain-Specific Languages

Not all programming languages are general-purpose. Some languages are built for specific domains:

  • SQL: A language for describing data queries
  • CSS: A language for describing appearance
  • Regular expressions: A mini-language for describing text patterns
  • HTML: A language for document structure

Domain-specific languages exist because general-purpose languages can be clumsy for certain problems, the way a Swiss Army knife is clumsy for actual carpentry. A DSL doesn’t try to do everything. It picks one job and does it well. You wouldn’t use JavaScript to query a database (well, you could, but you’d be making your life harder), and you wouldn’t use SQL to build a website.


These concepts underpin the choices language designers make. Once you know what to look for, you can read a language’s type system and memory model as a record of the trade-offs its designers chose to live with.