6. The Milestone 1 keyword set
- Status: Accepted — amended for Milestone 2 (see below)
- Date: 2026-09-02
Amendment (2026-09-03, Milestone 2): four keywords were added for exceptions —
try,except,finally,raise(ADR 0017) — taking the set from 19 to 23. Each is load-bearing and none has an alias:try/except/finallyare three distinct block roles that cannot share a word, andraiseis a statement, not a function (it unwinds; it has no return value and cannot be passed around).raise/exceptwere already listed as "deferred to a later milestone with its own ADR" below. The module keywordsimportandasfollow in the same milestone (that ADR carries their justification), which will bring the set to 25.
Context
"A small, deliberate set of keywords — nothing bloated" is a core design goal. The keyword set needs to be fixed early because it affects the lexer, the grammar, and what identifiers user code may use.
Decision
Milestone 1 defines exactly these 19 reserved words:
| Group | Keywords |
|---|---|
| Functions | fn return |
| Conditionals | if elif else |
| Loops | while for in break continue |
| Boolean logic | and or not |
| Literals | true false nil |
| Classes | class super |
| Empty block | pass |
Rationale for the debatable members:
fnoverdef/func/function— shortest unambiguous choice.elifoverelse if— one token, no nesting ambiguity, matches the single-keyword-per-concept style.and/or/notas words, not&&/||/!— they read as English, they cannot be confused with future bitwise operators, and Korrin has no C heritage to honour.selfis not a keyword. It is a conventional identifier — the name of a method's first parameter (0005). Using it outside a method is an ordinary "cannot findself" error, which is clear enough; making it a keyword would buy a marginally better message at the cost of one more reserved word and a special case in the resolver.superis a keyword, becausesuper.methodis special syntax: there is no value to bind a plain identifier to.passexists because indentation-defined blocks cannot be empty (0001).
Deliberately not keywords in M1: self, import, try, raise, catch,
let, var, const, match, lambda, global, nonlocal, async, await,
yield, with, del. Each is either deferred to a later milestone with its own
ADR or ruled out by another decision (let/var by
0011; global/nonlocal likewise).
Consequences
- The lexer's keyword table is a fixed 19-entry match.
import/try/raiseland later and will each get an ADR when their design is settled; user code today may use those words as identifiers, and reserving them later is a documented breaking change. Accepted for a pre-1.0 language.- Booleans-as-words means
notparticipates in operator precedence as a unary operator, handled in the Pratt parser.
Alternatives considered
- Symbol operators for logic (
&&,||,!). No benefit here; costs readability and a lexer that has to distinguish&/&&. - Reserving the post-M1 words now. Would break fewer future programs, but reserves words for features whose design (and therefore whose exact keywords) is not yet decided. Prefer to reserve a word when its ADR lands.
deffor functions. Fine, butfnis shorter and equally clear.