c6ba0677f0
cycles/ one file per Ishikawa -> scientific method -> Six Sigma loop, named
for the DEFECT not the fix, carrying the commit record as written at
the time
findings/ what the cycles produced, cross-cut: live bugs, architecture answers,
and defects in my own measurement
The organising finding is that predictions which came back FALSE produced every
significant result. Eleven of sixty-one failed, and those eleven found: that the
arity table was not drifted but 40% incomplete; that the AST traversal is
irreducible and only rules and judgments move; that guards could refuse through
the seam after all; and that routing el_bin_lookup through the gate did NOT fix
the SIGSEGV, because the fallback strlen was the hazard -- a wrong fix I would
otherwise have shipped as verified.
One cycle was run without committing predictions first and had to be discarded
as rigged. It is kept, in full, as 18-async-half-expressible.md.
65 lines
3.0 KiB
Markdown
65 lines
3.0 KiB
Markdown
# c has no closure syntax
|
|
|
|
One `Ishikawa → scientific method → Six Sigma` loop. The record below is the
|
|
commit message as written at the time, before the outcome was known to anyone
|
|
reading this file.
|
|
|
|
## Record — `2bed848`
|
|
|
|
```
|
|
EXPERIMENT: hand the construct the body as a real closure
|
|
|
|
ROOT CAUSE of the weaker design: "C has no closures" was taken as a fact about
|
|
what is possible. It is a fact about one grammar. Every C++ lambda, every Go
|
|
closure, every Rust closure compiles to a struct of captured values plus a
|
|
function pointer -- which is what is emitted here. Codegen emits C; it is not
|
|
written in C's syntax, and the distinction is the whole difference between a
|
|
construct that can only decide whether to repeat and one that controls
|
|
invocation.
|
|
|
|
It would also have crippled the JS backend, which has closures natively, for a
|
|
limit that applies only to the C one.
|
|
|
|
PREDICTIONS AND RESULTS
|
|
1 env struct + thunk taking void* TRUE
|
|
2 fails to compile: struct redefinition FALSE -- C allows the
|
|
inner declaration to shadow. Prediction wrong; C is more permissive than
|
|
assumed. A different real defect surfaced instead: a wrap with no exit
|
|
construct emitted `(EL_STR("f"), EL_STR(""), __r);` -- a call to an empty
|
|
target -- because has_exit was reused as "needs a wrapper" and the exit line
|
|
was emitted unconditionally. Fixed.
|
|
3 compiles when the target is declared in El FALSE -- and this is
|
|
the root cause worth keeping: El has ONE type, el_val_t = int64_t. El's type
|
|
system cannot describe a callable, so `extern fn` and the real signature
|
|
cannot be made to agree in El's own vocabulary. The fix is not a cast:
|
|
codegen DEFINES the wrap calling convention, so codegen emits the extern
|
|
declaration. The convention is not El-expressible; it is emitted.
|
|
4 target controls invocation, 0..N times TRUE
|
|
5 existing @manager output byte-identical TRUE
|
|
6 compiler fixpoint holds TRUE
|
|
7 emitting the convention makes it compile TRUE
|
|
|
|
MEASURED
|
|
base(5) wrapped by a target that invokes the body twice and sums -> 10
|
|
never_runs(5) wrapped by a target that never invokes it -> 999
|
|
|
|
Neither is expressible by "decide whether to repeat". This supersedes the
|
|
repeats_body experiment on experiment/repeats-body, which was built around the
|
|
mistaken limit.
|
|
```
|
|
|
|
## Record — `7d01608`
|
|
|
|
```
|
|
land wraps_body: a construct controls invocation
|
|
|
|
Proven on experiment/wraps-body (2bed848): base(5) wrapped by a target that
|
|
invokes the body twice returns 10; a target that never invokes it returns 999.
|
|
Neither is expressible by deciding whether to repeat.
|
|
|
|
Root cause it corrected: 'C has no closures' is a fact about one grammar, not
|
|
about what can be emitted. And El's single type (el_val_t = int64_t) cannot
|
|
describe a callable, so codegen emits the calling convention rather than asking
|
|
El's type system for something it structurally cannot say.
|
|
```
|