From 7be57efe185c341242c0f07dc60eeea8f12c3c1f Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sun, 13 Sep 2026 13:09:25 +0700 Subject: [PATCH] A type variable is marked, because absence is a bad thing to give meaning to --- NEXT.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/NEXT.md b/NEXT.md index 2973abd..b514497 100644 --- a/NEXT.md +++ b/NEXT.md @@ -1,3 +1,37 @@ +## Decided by the author, 2026-09-13: a type variable takes a `$` sigil + +**This overrides plan.org**, which says under Types: *"Lowercase type names are variables, Capitalized are +concrete — no sigil."* That rule is withdrawn. Taken as provisional, to make progress rather than as a final +design, and expected to be revisited after some real use. + +```lisp +(defn swap [xs [$t] i i32 j i32] () ...) +``` + +Three reasons, the third being the one that actually forced it. + +1. **There is no binding site without a sigil.** Nothing distinguishes where a variable is introduced from where + it is used. +2. **Introducing one is invisible.** `check.ml:535-562` resolves builtins, aliases, structs, unions, enums, then + near-miss, and *then* treats any leftover lowercase name as a type variable. So a lowercase name nobody has + heard of silently becomes a type parameter, and a mistyped type makes the function **more** permissive instead + of failing. The `near_miss` guard at line 553 exists for exactly this hazard and only reaches names close to a + known one — the comment there says so. `[elem]` is not close to anything and would become generic silently. +3. **Brackets carry two opposite rules for the same lexical thing.** In `[n t]`, `check.ml:563` resolves `n` + against `env.consts` and *errors* if it is absent, while `t` becomes a *variable* if absent. Absence means + "mistake" on one side of the bracket and "new parameter" on the other. + +The rule is also not the one plan.org states. It is not case-based: `i32`, `f32`, `bool` and `string` are all +lowercase and concrete. What the code actually does is **treat any unresolved lowercase name as a variable**, +which is an absence rule, and absence is a bad thing to give meaning to. + +**Open, and deliberately not decided here:** whether a *use* after the binding is `$t` or bare `t`. Odin binds with +`$T` and uses bare `T`. Left to whoever builds it, to be reported with the reason. + +**Also open: `$n` in length position**, Odin's `$N: int`, which is what would make a function generic over array +length rather than only element type. Not in the spike unless it falls out for free; the spike is to report what it +would cost. + ## To discuss: five gaps the raylib examples hit and could not close Found by the lane that ported `core-2d-camera`, `core-scissor-test`, `core-window-flags`,