The colon belongs to keys, and Map follows Odin rather than Clojure

This commit is contained in:
Joseph Ferano 2026-09-12 12:07:06 +07:00
parent eb98c5859a
commit 5badf6658b

43
NEXT.md
View File

@ -267,6 +267,49 @@ this closes nothing off. That section stays open for the record but is no longer
~~**5. File I/O — `slurp` and `barf` — is the next stdlib work**~~ **Built.** It was the next stdlib work, after `Vec`, because `slurp` returns a string whose
length is not known until the file is read and therefore cannot exist before an allocator does.
## Decided later the same day, and queued
**6. A field label is written with a dot, not a colon, and the colon is reserved for keys.** `{.x 1.0 .y 2.0}`
replaces `{:x 1.0 :y 2.0}` in struct construction, and the same change applies where destructuring names a field.
The delimiter is what makes it unambiguous, which is the author's argument and it holds: `(.x v)` is a call and
therefore an access, `{.x 1.0}` is a brace form and therefore a construction. Today the dot already means "read a
field" and the colon means both "field label" and "enum member", which is the ambiguity the change removes.
**The reason to do it before `Map`, not after.** A map literal will want to be `{:key value}`. If struct
construction owns that exact spelling, map literals and struct literals are the same syntax and the checker has to
tell them apart from context. Reserving the colon for keys — map keys and enum members — keeps the two visibly
distinct. Doing this after `Map` lands means changing both; doing it now means changing one.
Cost: ~284 sites across 45 `.flan` files, mechanical. **Queued rather than started** only because it touches nearly
every Flan file in the repo, including ones a running lane held. Run it when the tree is quiet, before step 4.
One thing to decide with it: destructuring uses the colon two ways — `{inner :field}` names a field, which should
become a dot like any other field, and `{:keys [x y]}` where `:keys` is an instruction to the compiler rather than a
field name, which arguably stays a colon. Settle both in the same pass rather than leaving the rule half-applied.
**7. `Map` follows Odin's implementation.** Read `base/runtime/dynamic_map_internal.odin` before writing any of it;
the checkout is at `~/Repositories/Odin`. Three properties are the ones worth copying, and they are stated in its own
header comment:
- **Open-addressed Robin Hood hashing at a 75% load factor.** No buckets, no per-entry allocation, and probe
distances stay even because a later arrival steals a slot from an earlier one.
- **Cache-line-aligned `Map_Cell` packing**, so no single key or value ever straddles a cache line and a linear probe
walks memory in a cache-friendly order. This is the part a hand-rolled open-addressed map usually gets wrong.
- **`uintptr` throughout** for sizes, masks and offsets, to keep sign-extension and masking instructions out of the
probe loop.
Its static/dynamic split is the same type-erasure this project already committed to: `Map_Info` carries size,
alignment and offsets, and the compiler emits the hash and equality pair per key type. `spec-memory.md`'s
structural-key restriction holds this to the built-in key set, so there is no dispatch to design.
**Why this will not be Python's dict.** Worth recording because it is the question that prompted the decision.
Python's dict algorithm is fine; what makes it slow is that every key and value is a separately allocated, reference-
counted object, and hashing and comparison go through indirect calls that cannot be inlined. Flan stores raw bytes
and compiles the hash and comparison concretely at each use. That difference is most of the gap before any
algorithmic cleverness. **jank is not the model** — it is Clojure, so its maps are persistent with structural
sharing, which plan.org rules out by name because shared structure destroys the clear ownership that is the whole
reason there is no collector.
## Blocked and unfinished
Everything below was found, decided or half-built and then stopped. Each says what blocks it. Nothing here is a