plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


06d3318 — Peter John 2026-11-04T20:26:00+05:30
docs: decide to remove traits and union enums (records with embedding + override instead)
docs/backlog.md CHANGED
@@ -8,7 +8,7 @@ Open work, in the order the user queued it, plus smaller items found during buil
8
8
  - **Explicit function generics** (user 2026-11-04: right after cleanup phase 2) — functions declare their generics (`fun map[B](...)`) instead of every single capital letter being a generic; allows longer generic names and one-letter concrete types/tags. Grammar change + about 140 signatures in std/examples. Phase 2's "generics by scope" makes this mostly a grammar + signature rewrite.
9
9
  - **Io as a built-in primitive with extern methods** (user 2026-11-04: LAST, once the whole compiler refactor and explicit generics are done) — `docs/plans/2026-11-04-io-primitive-extern-methods.review.md`. `primitive Io` with `extern fun f(self, ..)` methods replaces the ~55 top-level externs + forwarding `record Io` methods. A fake/recording `Io` comes later via a trait or language mocks.
10
10
  - **Move the Rust code into `compiler/`** (user 2026-11-04: once all the refactoring is done) — every Rust crate (plum-core, plum-checker, plum-wasm-codegen, plum-cli, plum-lsp, plum-host, plum-test-support, plum-runtime, plum-game) goes under `compiler/`; `plum-std` and `plum-examples` stay at the top level. Mechanical but touches hardcoded paths: workspace `Cargo.toml` members, every `CARGO_MANIFEST_DIR/..` repoRoot (test-support, tests, cli), the loader's std lookup, the checker's `isStdFile`/`isIoFile` path tests, `cmdBuild`'s runtime manifest path, plum-game web-test fixtures, scripts/, Makefile.toml, plum-tooling (vscode/tree-sitter paths), README and docs links. Open question for then: keep the `plum-` prefixes inside `compiler/` or drop them (`compiler/core`, …).
11
- 2. **Native inline variants, then decide union enums** — compile inline variants directly as struct subtypes of their enum and delete the hidden-record lowering (`hoistInlineVariants`, the `List__Cons(Cons(..))` wrappers, union forwarders). Then decide whether user-facing union enums (`enum X = A | B` of records) stay as a thin feature or fold into traits; if they go, `JsonParse` in `plum-std/Json.plum` becomes inline variants and the union examples (`unions.plum`, `struct_union_members.plum`) are rewritten. `unboxed_variants.plum` is really a compiler probe: move it to a codegen test. (Decision record §8b.)
11
+ 2. **Simplify the language: no traits, no union enums, native inline variants** (decided by the user 2026-11-04; runs right after compiler-cleanup phase 3a, before explicit generics and 3b; decision record §13). Traits are removed as a language feature and replaced by records embedding records with subtyping + `override` dispatch (a `Ship` embedding `Node` is accepted wherever a `Node` is, and calls dispatch to Ship's overrides — the scene graph's `trait Actor` becomes a base record). Union enums (`enum X = A | B` of records) are removed: `JsonParse` and the union examples become inline-variant enums, union syntax becomes an error. Inline variants compile natively as struct subtypes of their enum, deleting `hoistInlineVariants`, the `List__Cons(Cons(..))` wrappers, union forwarders, `union_lower` and the checker's union plan. `unboxed_variants.plum` is a compiler probe: move it to a codegen test. Needs its own review plan.
12
12
  3. **Benchmark** before FBIP (user: FBIP waits for it).
13
13
  4. **FBIP: no heap mutation** — persistent std collections updated in place when unique, Koka-style `fip` functions as a checked in-place guarantee, a reference count used only as a uniqueness check if static proof falls short. Worklist = the `mut` fields left today (see below). (Decision record §9.)
14
14
  5. **One product type, `struct`** — after FBIP, merge `record` into an immutable `struct` with compiler-chosen boxing (optional hint, shown by `--explain`). (Decision record §9b.)
docs/decisions/2026-11-language-and-scene-decisions.md CHANGED
@@ -119,6 +119,16 @@ A record of the design decisions taken in the 2026-11-03/04 sessions, with the r
119
119
 
120
120
  Gleam's data model (immutable records with `T(..x, f: v)` updates, custom types, enforced constructor/variable casing), Zig's effects and errors (`std.Io`-style capability, `!T`, error sets, `T?`, per-instantiation generics), Rust-style closed-world traits with static dispatch, an explicit `mut`-field escape hatch (to be removed by FBIP), and a whole-program wasm-gc compiler with a supercompiler. Unlike Gleam it tracks effects, keeps loops, and has traits.
121
121
 
122
+ ## 13. No traits, no union enums (2026-11-04)
123
+
124
+ The user decided to simplify the language before the compiler is refactored further (node ids, file splits):
125
+
126
+ - **Traits are removed.** Their role goes to records embedding records, like inheritance: a record that embeds another is a subtype of it, is accepted wherever the base is, and may `override` base methods; calls on a base value dispatch to the override. The scene graph's `trait Actor` becomes a base record.
127
+ - **Union enums are removed.** `enum X = A | B` over records goes; `JsonParse` and the union examples become inline-variant enums (`A(..) | B(..)`), compiled natively as struct subtypes of the enum.
128
+ - **Why:** both features are the main sources of the compiler's extra lowering passes (trait stand-ins in embeds/ctors, hidden records for inline variants, union_lower and the address-keyed union plan that forces repeated type checks). Removing them first shrinks every later cleanup phase and simplifies codegen.
129
+ - **Order:** right after compiler-cleanup phase 3a; then explicit function generics; then cleanup 3b, 4, 5, 6.
130
+ - This supersedes §11's "has traits" and the enum/union split in §8b.
131
+
122
132
  ## 12. Smaller decisions
123
133
 
124
134
  - **wasmtime:** the GC heap starts at 64 MiB in every host, and the dev profile compiles wasmtime at opt-level 3.