Before the compiler

Designing a Programming Language

Who the language is for decides the type system, the memory model, the concurrency model and the execution strategy. Every other answer in the domain follows from this one.

Who Is the Language For?

Every downstream decision — type system, memory model, concurrency model, execution strategy, error handling — is decided by who is going to write the code and what happens when they get it wrong. Answer this badly and nothing after it can be defended.

Q · Before I decide anything about syntax or types, what question am I supposed to answer first?
The Questions a Language Definition Must Answer

A checklist that is not a checklist: nine questions every language answers whether or not its designers noticed, each with a compiler consequence, and each capable of contradicting the answer to another.

Q · What do I actually have to decide to have a language, rather than a syntax?
Syntax versus Semantics

Syntax decides which strings are programs; semantics decides what they mean. The reason to keep them apart is that a compiler phase can only enforce one of them, and almost every argument about a language is an argument about the wrong one.

Q · What is actually the difference between a syntax error and a type error, and why do languages draw the line differently?
Ergonomics Is a Compiler Feature

Defaults, diagnostics, orthogonality and the cost of the common case are design decisions with implementation consequences, not polish applied afterwards. The languages people call pleasant paid specific, identifiable prices for it.

Q · Why do some languages feel good to write and others feel like an argument, and is that anything more than taste?
Choosing an Execution Model

Implementation strategy is not a property of a language, but a language definition can make some strategies expensive and others impossible. This is the lesson about which features write cheques the execution model has to cash.

Q · How does what I put in the language decide what implementations of it are possible?
Choosing How Memory Is Managed

Five answers — manual, tracing collection, ownership, reference counting and regions — and for each one, the code the compiler has to emit that the programmer never wrote.

Q · Which memory management model should my language have, and what does each one make the compiler responsible for?
Choosing a Concurrency Model

Threads and locks, async/await, actors, CSP channels and data parallelism are five language design decisions, and each one hands the compiler a different job: a memory model to obey, a state machine to build, an isolation rule to check, a scheduler to emit calls into, or a loop to prove independent.

Q · Which concurrency model should the language have, and what does each one force the compiler to do?
Interoperability Is a Language Design Decision

A language that must call existing code has already had its data representation, its error model and its threading model partly decided for it. The C ABI is the lingua franca not because it is good but because everything already speaks it.

Q · What does it cost my language to be able to call, and be called by, code written in something else?
The Trade Nobody Escapes

Seven requirements, seven answers, and no row where the answer is a language. Every decision in this module buys one property by paying for it somewhere specific, and the discipline is naming the payment out loud.

Q · Given what I actually need, which set of language design decisions follows — and what am I paying for it?