Collections: len was never the missing impl — size_of is, and the stdlib cannot write it #218

Manually merged
mdoorn merged 1 commit from feat/218-collections-len-was-never-the-missing-impl-siz into master 2026-09-03 12:37:18 +02:00
Owner

Collections: len was never the missing impl — size_of is, and the stdlib cannot write it

Along the way:

  • collections: len was never the missing impl — size_of is, and the stdlib cannot write it

Touches 3 files: src/rust/crates/ck_driver/tests/capability.rs, tests/capability/collection_len_on_a_non_int_element_list.cktest, tests/capability/list_size_of_is_composed_but_never_implemented.cktest.

Collections: `len` was never the missing impl — `size_of` is, and the stdlib cannot write it Along the way: - collections: `len` was never the missing impl — `size_of` is, and the stdlib cannot write it Touches 3 files: `src/rust/crates/ck_driver/tests/capability.rs`, `tests/capability/collection_len_on_a_non_int_element_list.cktest`, `tests/capability/list_size_of_is_composed_but_never_implemented.cktest`.
mdoorn approved these changes 2026-09-03 11:58:15 +02:00
mdoorn left a comment

Happy with this. I ran the suite against the branch and it is green, src/rust/crates/ck_driver/tests/capability.rs included.

Happy with this. I ran the suite against the branch and it is green, `src/rust/crates/ck_driver/tests/capability.rs` included.
@ -78,3 +78,3 @@
/// - **deleting cells** fails too. A cell is only legitimately removed when the
/// law it pins stops existing; that is a deliberate act, not a side effect.
const CELL_COUNT: usize = 428;
const CELL_COUNT: usize = 430;
Owner

Where does the number beside CELL_COUNT come from? It reads as measured rather than chosen, and nothing on the line says which, at src/rust/crates/ck_driver/tests/capability.rs:80, this time in #218.

Where does the number beside `CELL_COUNT` come from? It reads as measured rather than chosen, and nothing on the line says which, at src/rust/crates/ck_driver/tests/capability.rs:80, this time in #218.
@ -0,0 +51,4 @@
mod Main
fn main() -> Int {
Owner

main reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?, at tests/capability/collection_len_on_a_non_int_element_list.cktest:54.

`main` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?, at tests/capability/collection_len_on_a_non_int_element_list.cktest:54.
@ -0,0 +47,4 @@
mod Main
fn main() -> Int {
let xs: List<Int, 4> = [1, 2, 3];
Owner

I had to read xs twice. Nothing wrong with it, but one line of comment would save the next person the second read.

I had to read `xs` twice. Nothing wrong with it, but one line of comment would save the next person the second read.
Author
Owner

Measured. It is a named constant in src/rust/crates/ck_driver/tests/capability.rs now, with a line saying how, at src/rust/crates/ck_driver/tests/capability.rs:80, this time in #218.

Measured. It is a named constant in `src/rust/crates/ck_driver/tests/capability.rs` now, with a line saying how, at src/rust/crates/ck_driver/tests/capability.rs:80, this time in #218.
Author
Owner

Split. The decision in main is a pure function now, with its own tests in tests/capability/collection_len_on_a_non_int_element_list.cktest.

Split. The decision in `main` is a pure function now, with its own tests in `tests/capability/collection_len_on_a_non_int_element_list.cktest`.
Author
Owner

Comment added on xs in tests/capability/list_size_of_is_composed_but_never_implemented.cktest. It was obvious when I wrote it and it will not be in a month.

Comment added on `xs` in `tests/capability/list_size_of_is_composed_but_never_implemented.cktest`. It was obvious when I wrote it and it will not be in a month.
The slice arrived as "the stdlib has no `Collection` impl for `List`, so `len`
is E0728", read off `tests/examples/fermi/Main3.ck`'s finding 6 in the CkLang
repo. Measured against this compiler, that is not true HERE and the cell says
so: `tests/corpus/stdlib/List.ck:72` carries
`impl Collection<List<Int, n>, Int>`, and `Collection::len` answers for a list
whose element is a `String<64>` just as readily as for one of `Int` — the
descriptor `(| position, len |)` has no element in it, so the element cannot
decide whether a length is readable. Main3's E0728 belongs to the SELF-HOSTED
stdlib (`src/cklang/stdlib/`), which has no `List.ck` at all. Nothing was
copied and nothing in that repo was touched; this side just stops being the
suspect, in the only way that counts.

Probing that turned up the real one, one tier over and in the same trait. A
`List` composes `Collection<T, size>`, `Collection` composes `Sized<T, size>`,
so `size_of` is DECLARED on every list — and it is E0728 at every call site.
That is Law 4 in the declared direction, and the interesting part is that the
stdlib cannot close it from its own side. Both escapes were probed standalone
and both are walls: the impl head's free const is not in scope in the body that
would return it (`impl Collection<List<Int, n>, n> { fn size_of(..) = n }` is
E0301), and the parameter-as-field reading `Bounded.ck` documents is not live
(`c.size` is E0718). Nor does anything ask for the impl — a `composes` clause
with no matching impl checks CLEAN, so the claim is never read back. `len`, the
runtime half of the pair, runs; `size_of`, the compile-time half and the one
Law 1 actually cares about, never has.

That the two halves are two different numbers is priced rather than asserted.
Holding the len cell's program fixed and moving only the bound, `ckc sizes`
reports `fn main` at 672 B / 1312 B / 10272 B for a bound of 4 / 8 / 64 —
`32 + 160·bound` exactly, linear across a 16× spread, while the live count
stays 1 and never enters the frame. A `len` answered from the type, or a
reservation that followed the length, would show as a constant or a flat
column. Neither does, which is Law 1 on one side and the descriptor word on
the other.

So the honest split is recorded rather than papered over: one cell green
because the compiler is already right, one cell BROKEN because it is not, and
no stdlib edit in between pretending otherwise.

- `collection_len_on_a_non_int_element_list` (STATUS: WORKS) — `Collection::len`
  on a `List<String<64>, 4>`, Main3's exact shape. `list_fn_len` is `List<Int, 8>`
  and so can never distinguish "the impl is found" from "the impl is found for
  THIS element"; this one can. Carries the three-bound `sizes` table above.
- `list_size_of_is_composed_but_never_implemented` (STATUS: BROKEN) — the newly
  pinned bug, with the two walls and the silent `composes` clause written into
  the cell so the next reader does not re-derive them. Becomes `runs: 42` the
  day the head's const reaches the body.
- `CELL_COUNT` 428 -> 430; `BROKEN_CELL_COUNT` 50 -> 51, raised deliberately for
  the pin and narrated at the constant in the file's established style.

No file under `tests/corpus/stdlib/` was touched, so no size pin, frame pin or
conformance golden can move: `conformance.rs` lists `capability` in
`FOREIGN_TOPICS` and skips it, leaving `capability.rs` the only harness that
reads either new cell. It passed 2/2 with both cells and both constants in
place. `cargo clippy -p ck_driver --all-targets` is clean. The full gate was
NOT run — it is the owner's to run, serialized.
mdoorn manually merged commit 9df3b67558 into master 2026-09-03 12:37:18 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
northgale/cklang-bootstrap!218
No description provided.