Types phase 3: safety & control flow — option / result + tagged-union enums #53
Labels
No labels
area:ci
area:docs
area:input
area:net
area:rendering
area:repo
area:stdlib
area:tooling
area:types
cleanup
dx
priority:high
priority:low
priority:medium
proposal
status:in-progress
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: workshopsoft/ludic#53
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to #1 (proposal), phase 3 of the phasing.
option — 'no target' / 'empty slot' without magic
-1sentinels (Rust/Swift; C# nullable).result<T, E> — fallible ops (load, parse, net) without out-params or silent failure. Note the language already has
try EXPR else { ... }(#46) recovering a fallible result as a value; this phase generalises that into a first-classresulttype.tagged-union enums (payloads) — model game state, events and tile kinds as one value and
matchon it. Todayenumis only int constants; this adds per-variant payloads and exhaustive matching (Rust/Swift; C# records + pattern matching).Phase 1 (IVec2 + Rect) shipped in the #1 thread.
Shipped —
option, completing the option/result safety pair (790eda6)Types phase 3 is about safety and clean control flow. Its two concrete sum types are now both in:
result/ok/err/try/is_ok/is_err— already shipped in #46. A fallible function returns aresult; the caller recovers a value withtry EXPR else { … }(the failure message binds toerror).option— new here. The "maybe a value" companion, in the same idiom:some(v)— wrap a present value (any i32-width scalar: int/fixed/bool/entity)none()— the empty case, a missing value with no magic-1sentinelis_some(o)/is_none(o)— test presenceunwrap_or(o, fallback)— read the value, or a fallback when emptyRepresented as a heap
%Option = { i32 present, i32 value }, as bare builtins guarded byfind_fn(a user function of the same name still wins) and gated byg_uses_option, so a program that does not use them compiles byte-identically — the same additive design asresult.Tagged-union enums → #56
The third item, tagged-union
enums with payloads and exhaustivematch, is the one genuinely deep type-system feature in the proposal, and the project's own #46 changeset already flagged it as "sequenced after the tagged-union type system". It cannot land as an additive namespace/builtin: it needs parser support for variant payloads and constructor syntax, a tagged value ABI,match-arm payload binding, and an exhaustiveness/checking pass (Ludic has no validation pass yet). Bundling that invasive change here would risk the bootstrap fixpoint and every golden render. I have split it into its own tracked issue, #56, exactly as the oversized remainder of #1 was decomposed.Interim coverage for tagged data: the
Value.*tree (#44) already models dynamic tagged values (a tag + heterogeneous kids) with a runtimeValue.kindmatch, andenum+matchcovers the int-tag state-machine case.Wired end to end:
emit_callcodegen +%Optiondecl (emit_decl) +g_uses_option(emit_core), reseeded C-free seed, full vocabulary sync (header / JetBrains / TextMate), per-builtin docs + inventory, and a self-asserting example (examples/library/optionresult.ludic, 12 assertions exercising both option and result, in the regression suite). All suites green:x test85/85,x selfhost-test30/30 (golden renders byte-identical, bootstrap fixpoint holds),x test-tools30/30,check-impl/check-vocabulary/check-docs.Closing phase 3 (option + result delivered); tagged-union enums continue in #56.