Reference
The canonical inventory of the language: keywords, builtin types and decorators. It serves two purposes: being the single list of what lives in global scope (the non-poisoning of section 1 in table form), and answering the question that the raw count of decorators provokes, “isn’t that too many decorators?”.
Keywords
Section titled “Keywords”The words woven into the grammar. They are the irreducible global scope: reserved in every program, and for that reason kept to a minimum.
- Declaration:
fnletvarmutconstdeclaliasunionmoduleuse - Control flow:
ifelsematchloopinbreakcontinuereturndefercatchyield - Concurrency:
spawntimeout - Compilation and safety:
comptimeunsafeassertassume - Visibility:
pubpriv - Conversion:
as - Literals:
truefalse
Thirty-two in total. What looks like a keyword but is not (and why):
type: not a keyword, it is the kind (the type whose values are types, builtin, section 10), and it lives in the list of builtin types. Whoever declares a type isdecl;typeis what you write when something is a type (T: type,-> type). There is notype Name = …: new structure isdecl, an alias isalias(section 2).select: does not exist; it is the subjectlessmatch(section 4). One construct less for the same power.self: does not exist; a method’s receiver has a free name (fn (d: *Dog) ...), and a process’s self-reference is the methodruntime.self()(section 3). No reserved magic name.null: does not exist; absence isOptional[T](section 6), and C’sNULLbecomesOptionalat the boundary (section 17).and/or/not: the language uses the symbols&&/||/!.generator: it is the decorator@generator(section 11), not a keyword.print/panic: they are not keywords nor builtins; they live inio/runtimeand are imported (section 1). The global scope carries no functions.
Builtin types
Section titled “Builtin types”The types that the core syntax presupposes, available without import because the grammar mentions them (a Result in the catch, a Channel in the <-, an int in a literal). It is the closed list of what lives in global scope; all the rest is imported stdlib.
- Result and absence:
Result[T, E](variantsOk/Err),Optional[T], and the error setserror{...}(section 7) - Concurrency:
Channel[T](section 4) - Numeric: the arbitrary-width family
iN/uN(1 to 65535) and the aliasesint/uint/isize/usize/byte/bit(byte=u8,bit=u1); the floating-point familyf16/bf16/f32/f64/f128(aliasfloat);bool;noreturn(the bottom type of divergence) (section 14) - Text:
string, and the iteration unitsbyte/codepoint/grapheme, withcharas an alias ofgrapheme(section 16) - Aggregates:
[N]T(fixed-size array) and[]T(slice) - Pointers:
*T(pointer-to-one) and[*]T(pointer-to-many, N contiguous that is owned, the basis of collections, section 6); the allocation handlesPtr/RawPtrof the memory layer (section 5) - Comptime:
typeand the proposition universeprop(types and propositions are values at comptime, sections 10 and 21);Generator[T](section 11); and the type-operatordual, which mirrors a session protocol (section 21) - Time:
Duration(theu64of nanoseconds oftimeout, section 14)
What is not builtin, despite seeming fundamental: the collections List/Map/Set (package collections), the interfaces Display/Serializable/Iterator/Writeable (fmt/encoding/io), the managers MemoryManager/MemorySource (package mem), the arbitrary-precision durations Duration[T]/ArbitraryDuration (time), the proof and tactic machinery (Eq/Refl and the Goal/Stack/tactic library of section 21, all Makoto over the proof primitives), and every function (print in io, panic in runtime, reflect/fail in compiler, size_of/align_of/offset_of in mem). The line is deliberate: builtin is only what the syntax cannot express without it; the rest is imported, and whoever does not use it does not pay.
Decorators, by domain
Section titled “Decorators, by domain”A keyword is a core concept; a decorator is a subsystem label. The division between the two categories is not aesthetic, it is what each one means. A keyword is a core concept, an act every program exercises (define, commute, repeat, declare): the common vocabulary. A decorator is the label of the subsystem something belongs to: @mm says “this is memory”, @supervisor says “this is concurrency”, @cimport says “this is FFI”. That is why the raw count scares and should not: you never face all forty at once, you face those of the subsystem you are working in. The decorator is not syntax noise, it is the boundary stamp that says which system you entered (section 1).
The raw count scares, it is forty. But the raw count is the wrong metric, because decorators group by domain, and a program touches one or two domains, never the forty. What weighs is not the total in the manual, but rather how many you meet in the task ahead. Grouped:
- Memory (6):
@mm@transfer@promote@pin@unpin@limit. Allocator, ownership and movement (section 5). It is opt-in: with the default GC, you write none of them, because they are the surface of whoever descends to@mm(none)/arena. - Contracts (2):
@requires@ensures. Verified pre- and post-conditions (section 5). They appear only where you want the check. - Concurrency and resilience (2):
@supervisor(supervision trees, section 8),@register(named process registration, unique, or in a group via@register(name, group), section 3). - Composition (1):
@embeds. Promotion of methods and fields (section 2). - FFI with C (4):
@cimport@extern@callback@repr. The boundary with C (section 17). A pure program never types them. - Assembly (1):
@asm. Architecture and dialect on the function (@asm(x86, intel)) and register binding on the param or local (@asm(in, rax)); inline asm (section 18). The niche of the niche. - UI reactivity (4):
@state@derived@effect@context. Reactive state (section 20). They only exist in.mkoui, the extension that an ordinary.mkodoes not activate. - UI structure (6):
@component@server@client@jsimport@css@scope. Components, server/client boundary, scoped style (section 20). Also only in.mkoui. - Tests (3):
@test@testmode@bench. Test, mocking and benchmark (section 1). - Generators (1):
@generator. Functions that produce byyield(section 11). - Ownership discipline (2):
@must_consume@consume_once. Type-level linearity and affinity (section 21). Opt-in: only a resource you want the compiler to track exactly-once/at-most-once carries them. - Refinement (1):
@where. A predicate on a type (section 21). Appears only on the types you constrain. - Fences (2):
@pure@total. Effect and termination promises (section 21). Inferred by default; you write them where you demand the check, or where a comptime function enters a type. - Sessions (3):
@protocol@sends@receives. A channel’s protocol and its steps (section 21). Only aChanneltyped by a@protocolsees them; a plain channel never does. - Proof (1):
@proof. The fence that turns an indexed family or function into trusted logic (section 21). The niche of the niche: only a proved kernel carries it. - Model checking (1):
@spec. Safety and liveness of a process design (section 21); an extension, like the UI ones. It lives beside@supervisor, and a program without it never sees it.
The grouping is the answer to “death by a thousand decorators”: they do not rain together. A network service in GC touches maybe @supervisor and @register, two. Whoever descends to manual memory gains the six of memory, and none of UI. Whoever writes UI gains the ten of .mkoui, and none of asm. The four doors of C and the door of asm most never open. The density you feel is that of your domain, and each domain has a small count. It is the opt-in (section 1) applied to annotation: the sophistication stays available, grouped and out of the way until you summon it.
Implementation notes (reminders)
Section titled “Implementation notes (reminders)”Implementation notes, not design ones: choices of how to build, not of what the language is.
- Frontend in Go. The lexer, tokenizer and parser probably in Go, which opens a concrete door: using the TypeScript Compiler that Microsoft rewrote in Go to read the
.d.tsof the@jsimport(section 20), instead of reimplementing the TS type-checker from scratch. - LLVM backend now, own one later (section 18), pragmatic for the multiple targets and the cross-compile.
- Own calling convention later (section 23): we start by inheriting LLVM/C’s (free interop, no two conventions to maintain); an optimized internal convention comes together with the own backend.