plan.org describes containers, pools and classes as they are after the repeal

This commit is contained in:
Joseph Ferano 2026-09-25 07:37:37 +07:00
parent cf71caefc2
commit 918edfb0b5
2 changed files with 27 additions and 21 deletions

View File

@ -1966,9 +1966,13 @@ CLOSED: [2026-09-25]
The five predicates are the checker's five, with =integer?= in place of The five predicates are the checker's five, with =integer?= in place of
=copyable?=, and the section no longer names =(Handle $t)= or =pool-new=. =copyable?=, and the section no longer names =(Handle $t)= or =pool-new=.
** TODO plan.org's Data model section still describes move-only containers ** DONE plan.org's Data model section still describes move-only containers
"Owning containers move rather than copy on assignment" and "one =Vec= field CLOSED: [2026-09-25]
makes it move-only" predate the repeal, under which everything copies. The Data model section says assignment copies a container's header and the
copies alias one buffer. The memory tiers and the classes section name the pool
and generational handles as a library over a =Vec=, and the classes gate that
named =Handle= is replaced by what classes are as built. The milestone record
of what was frozen is left as history.
** DONE plan.org cites the wrong mechanism for jank's relinking bug ** DONE plan.org cites the wrong mechanism for jank's relinking bug
CLOSED: [2026-09-25] CLOSED: [2026-09-25]

View File

@ -5,7 +5,7 @@
Two documents are normative and are settled ahead of implementation. Anything in Two documents are normative and are settled ahead of implementation. Anything in
this plan that contradicts them is out of date. this plan that contradicts them is out of date.
- [[file:spec-memory.md][spec-memory.md]] — ownership, the four container types, - [[file:spec-memory.md][spec-memory.md]] — ownership, the four container types,
copies and moves, assignable places, generics without type classes, function copies, assignable places, generics without type classes, function
values. values.
- [[file:spec-conditions.md][spec-conditions.md]] — the six hard cases of - [[file:spec-conditions.md][spec-conditions.md]] — the six hard cases of
conditions/restarts: what ~signal~ returns, no-handler behaviour, restart conditions/restarts: what ~signal~ returns, no-handler behaviour, restart
@ -56,14 +56,15 @@ Allocators all the way down; ~malloc~ hidden behind them.
| Tier | Strategy | Cost | | Tier | Strategy | Cost |
|-----------+---------------------------------+----------------| |-----------+---------------------------------+----------------|
| Frame | arena, bulk reset each frame | free | | Frame | arena, bulk reset each frame | free |
| Entities | pool + generational handles | free | | Entities | a pool over a ~Vec~, in a library | free |
| Subsystem | region, freed wholesale | free | | Subsystem | region, freed wholesale | free |
| Dev/REPL | leaks by design, reset on reload| dev only | | Dev/REPL | leaks by design, reset on reload| dev only |
- Allocator is part of the calling convention, so a refcounted allocator can be - Allocator is part of the calling convention, so a refcounted allocator can be
added later without a language change. added later without a language change.
- Generational handles instead of pointers for cross-references: a stale - Generational handles instead of pointers for cross-references, written as a
reference is detectable, not undefined behaviour. library over a ~Vec~ rather than provided by the language: a stale reference
is detectable, not undefined behaviour.
- Symbols and code live in a permanent arena that only grows. - Symbols and code live in a permanent arena that only grows.
** Why no persistent collections ** Why no persistent collections
@ -93,8 +94,8 @@ world.
|-------------+-----------------+------------------+------| |-------------+-----------------+------------------+------|
| ~[n T]~ | inline, n items | copies | no | | ~[n T]~ | inline, n items | copies | no |
| ~[T]~ | ptr+len | copies the view | no | | ~[T]~ | ptr+len | copies the view | no |
| ~(Vec T)~ | ptr+len+cap | *moves* | yes | | ~(Vec T)~ | ptr+len+cap | copies the header | yes |
| ~(Map K V)~ | open addressing | *moves* | yes | | ~(Map K V)~ | open addressing | copies the header | yes |
~Vec~ and ~Map~ are monomorphic on element type and record their allocator. Not ~Vec~ and ~Map~ are monomorphic on element type and record their allocator. Not
a Lua-style array/hash hybrid — that is what makes Lua's layout and performance a Lua-style array/hash hybrid — that is what makes Lua's layout and performance
unpredictable. unpredictable.
@ -105,17 +106,15 @@ world.
returns ~(Option V)~; ~put~ is the ~()~-returning upsert. See returns ~(Option V)~; ~put~ is the ~()~-returning upsert. See
spec-memory.md for the deferred move-aware operations. spec-memory.md for the deferred move-aware operations.
- Operations: ~get~, ~put~, ~remove~, ~push~, ~pop~, ~at~, ~length~, ~update~. - Operations: ~get~, ~put~, ~remove~, ~push~, ~pop~, ~at~, ~length~, ~update~.
Copying is explicit: ~(clone m)~, and owning containers move rather than copy on An independent copy is explicit: ~(clone m)~. Assignment copies a container's
assignment. No ~!~ convention — nothing is immutable, so it header, and the two headers alias one buffer. No ~!~ convention — nothing is immutable, so it
would carry no information. No ~assoc~; it only existed as the copy-returning form. would carry no information. No ~assoc~; it only existed as the copy-returning form.
- ~const~ qualifier on references and slices: compile-time contract that a - ~const~ qualifier on references and slices: compile-time contract that a
callee will not mutate. Zero runtime cost. callee will not mutate. Zero runtime cost.
- Value structs copy on assignment — but only *value* structs. Ownership is - Structs copy on assignment. A struct with a ~Vec~ field copies the header, so
structural: a struct is a value type iff every field is, so one ~Vec~ field the two copies alias one buffer, as in Odin. Deep copies are always explicit:
makes it move-only. This is what keeps "copies on assignment" from meaning a ~(clone x)~. Structs without owning fields are the snapshot / undo / replay
shallow copy that aliases owned storage. Deep copies are always explicit: story; they need no separate type.
~(clone x)~. Value structs are the snapshot / undo / replay story; they need no
separate type.
- Literals live in read-only memory. - Literals live in read-only memory.
- *A global's initialiser may be computed.* A value the linker can write goes - *A global's initialiser may be computed.* A value the linker can write goes
into the image and costs nothing to start; anything else is stored at into the image and costs nothing to start; anything else is stored at
@ -156,8 +155,8 @@ identity, extensibility, and live schema changes:
Classes require a managed allocation strategy and runtime class/shape metadata, Classes require a managed allocation strategy and runtime class/shape metadata,
but *not necessarily a tracing GC*. The initial likely choices are a world or but *not necessarily a tracing GC*. The initial likely choices are a world or
session arena, pool allocation behind generational ~(Handle T)~ values, or an session arena, a library pool behind generational handles, or an explicitly
explicitly owned region. A small tracing GC confined to class instances remains owned region. A small tracing GC confined to class instances remains
an option if cyclic graphs prove burdensome; it never changes ~struct~ layout or an option if cyclic graphs prove burdensome; it never changes ~struct~ layout or
the C ABI. the C ABI.
@ -187,8 +186,11 @@ surprising lazy mutation on field access:
#+end_src #+end_src
The precise class syntax, inheritance, storage strategy, and migration API are The precise class syntax, inheritance, storage strategy, and migration API are
not frozen. Do not add classes until ordinary ~struct~, ~Handle~, and reload not frozen. What is built is narrower than this section: a ~defclass~ instance
semantics are working. is a dyn map with its class in the object header, and a redefined class
migrates each instance lazily at its next touch, so nothing enumerates live
instances (TODO.org, "defclass is a named dyn map with a shape tag" and "A
redefined defclass migrates its instances lazily").
Immutability also serves the optimiser: a value known never to be mutated can be Immutability also serves the optimiser: a value known never to be mutated can be
copied into registers and stack-allocated freely. Mutability is what forces heap copied into registers and stack-allocated freely. Mutability is what forces heap