diff --git a/NEXT.md b/NEXT.md index 963e2b1..d70afce 100644 --- a/NEXT.md +++ b/NEXT.md @@ -56,6 +56,51 @@ recording, range recording, or a per-allocator opt-out on speculation. **Note on classes:** `defclass` instances will carry shape metadata by design, so they get identification for free and do not need the registry. This is for plain structs, `Vec`, `Map` and pool storage. +## Queued: structural typing and tuples, as one piece of work + +They are the same feature — **a type identified by its shape rather than its name** — and building them separately +would mean building the same machinery twice. + +### Structural typing, decided + +**Compatibility requires identical layout: same fields, same types, same order.** Settled by the author, and it is +what makes the feature simple rather than hard — structural compatibility becomes "the same memory", which costs +nothing at run time and needs no copy, no reordering and no adaptor. The motivating case is `{.x 1.0 .y 1.0}` and that +order is natural anyway. + +**The representation is already structural.** `types.ml` does structural equality on resolved types, and a Flan struct +is exactly its C layout with no header or tag word. What is nominal is the *checking*, not the data — so this is a +front-end change. + +**Fields are writable on the ordinary terms**: by value a copy, through a `(Ptr T)` the original. Requiring identical +layout is what settles this; a reordering-tolerant version could not alias real storage and would have needed a copy. + +**Not an "explicit over convenient" question.** That framing was put and the author rejected it, correctly: the +standing rules about implicit numeric conversion and integers not becoming enums are about *lossy* things happening +silently. A structural match is exact. Strong typing and nominal typing are separate choices and this touches only the +second. + +**Flexible field order waits for classes**, deliberately — a class has an implementation-defined representation, so the +compiler owns the layout and order stops being observable. That is the right place to pay for flexibility, because a +class already carries identity and metadata and a `Vector2` should pay for neither. + +### Tuples + +**Anonymous structs with positional fields, passed and returned by value.** Decided in conversation. + +To settle while building: the **spelling** of the type, and whether it collides with anything in type position; the +**accessors**, given fields are positional rather than named; and whether **destructuring** extends to them — +`[a b]` over a fixed array already exists in binding position and is the obvious model. + +**Interaction with multiple return values, which are separately queued:** MRVs are *not* tuples — they are not values, +existing only at the return and the binding, so nothing stores or passes them (Odin, Go and Common Lisp all work this +way). Tuples are values. Build MRVs on the tuple machinery if that falls out, but do not conflate them: the current +customer for MRVs is `map-next!`, which uses three out-pointers because there was nothing better. + +**Note for the FFI:** `shim.ml` generates a C typedef per *named* struct, and an anonymous struct has no name to +generate one from. Either anonymous structs cannot cross the FFI — refused by name, which is the house rule — or the +generator learns to name them. Decide it rather than discovering it. + ## Picked up first, 2026-09-13 Three things, in order. The first two are one line each and unblock a real game.