Structural typing and tuples are one piece of work
This commit is contained in:
parent
83369196a9
commit
61c41ed27c
45
NEXT.md
45
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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user