← board

NilPy: a def as a VALUE (procedure pointer)

Replaces the scope of feature-nilpy-nested-def-as-value, which was filed on the belief that uforth needed CLOSURES. It does not — see [[decide-nilpy-closure-model]] for the measurement that corrected it. 162 of uforth's 205 inner defs capture nothing; what the corpus needs is the ability to pass a function around at all.

Repro

def w_dup(vm: VM) -> None:
    vm.push(vm.peek())

vm.define_word("DUP", native=w_dup)     # w_dup as a VALUE — not supported

Calling works; referencing the name does not.

Shape

pxx already has procedural types, SymProcSig/SymElemProcSig and AN_CALL_IND, so this is frontend wiring rather than new codegen:

Scope v1

The corpus is uniform enough to make v1 narrow: arity 1, -> None covers 186 of 205 natives ((VM) -> None). Support the general annotated signature if it falls out; do not invent a first-class function TYPE system for it.

An escaping def that implicitly captures an enclosing local stays a hard ERROR (zero corpus sites; keeps the closure fork open with no silent divergence). Explicit by-value capture is [[feature-nilpy-default-args-on-nested-defs]].

Gate

test-nilpy green with a .npy case diffed against CPython — define, store in a field and in a dict, pass as an argument, call through it, and two different functions through the same slot — plus --tier quick + self-host byte-identical.

Log