Structural typing and tuples are one piece of work

This commit is contained in:
Joseph Ferano 2026-09-13 09:09:29 +07:00
parent 83369196a9
commit 61c41ed27c

45
NEXT.md
View File

@ -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.