Host eval is clean — no bootstrap overhead, no self-hosted functions … #71
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
seq-lisp-2-backport
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
navicore/seq-lisp!71
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "map-filter-regression-fix"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
…in the host path, no regressions. The self-hosted reader/eval lives in
lib/reader/ as an additive library.
PR Review: Host eval cleanup — remove bootstrap, restore native map/filter/fold
Overall this is a sound direction — removing the bootstrap overhead from the hot path is the right call, and the design doc is admirably honest about what regressed and why. A few issues worth addressing before merge.
Critical:
notsilently disappears from host evalThe old bootstrap provided
notto the environment. This PR removes the bootstrap entirely but does not addnotto the dispatch chain. As a result,(not x)in the host eval now produces "undefined symbol: not" rather than a boolean.The test suite doesn't catch this because the only
nottests go throughseval-string(self-hosted eval path), not the host eval.tests/lisp/core/predicates.slisphas nonottests at all.Fix: add a native dispatch entry for
not(it's a trivial one-liner in Seq) alongside the other predicates, or add it todispatch-predicates. Either way, a test inpredicates.slispshould accompany it.Stale comment in
lib/bootstrap.slispThe file header still reads:
But
bootstrap-sourcewas deleted in this PR. The comment is now incorrect and will confuse anyone who reads it. The file should either be deleted (it serves no purpose if there's no longer an embedded bootstrap) or its header updated to reflect that it's no longer backed by anything insrc/eval.seq.Positive: iterative map/filter in self-hosted eval
The new
map/filterviareverse+foldinlib/reader/eval.slispis the right fix for the self-hosted stack overflow. Definingfoldfirst (somap/filtercan use it) is correct, andreverseis confirmed available as a builtin in the self-hosted eval.Positive: bootstrap overhead removed from hot paths
The previous approach re-evaluated the bootstrap source string on every call to
eval,eval-print,run-file,run-repl, etc. Replacingbootstrap-envwithenv-emptyacrosssrc/eval.seqandsrc/repl.seqeliminates this. No objections.Minor:
map/filteronly accept closures, not symbolseval-map-with-envandeval-filter-with-envevaluate the function argument and then checksclosure?. This means(map car '((1 2) (3 4)))will fail becausecarisn't an environment-bound closure. Theapplybuiltin handles this via the symbol-detection path (constructs(car (quote ...))and re-evaluates), butmapandfilterdon't get that treatment.This appears to be pre-existing behavior (the self-hosted closures had the same limitation), so not a regression from this PR, but worth noting as a known gap. The design doc's statement that "all interesting functions are recursive" is true, but first-class builtins in
mapwould meaningfully expand the language's expressiveness.Then-count arithmetic
15
thens for the updateddispatch-group4looks correct (was 12, added 3 for map/filter/fold).Summary
notremoved from host eval, no tests cover itlib/bootstrap.slispheader references deletedbootstrap-sourcemap/filterdon't accept builtin symbols as fn argPR Review: Host eval cleanup — bootstrap overhead removed
This is a clean architectural win. Removing the bootstrap eval path from the host cuts startup overhead and eliminates the self-hosted/native duplication that caused the stack overflow regressions. Overall the implementation is sound. A few things worth noting:
Potential issue: empty if-body in
eval-not-with-env(eval.seq ~line 4209)The empty
ifbody works correctly — the error EvalResult stays on the stack and is returned — but this idiom is easy to misread and could silently swallow a logic error if the stack depth ever changes. The more idiomatic pattern used elsewhere in this file has an explicit error branch. Not a blocker, but worth a comment at minimum.Missing regression test for large-list map/filter
The stated motivation for reverting
map/filter/foldto native was a stack overflow at ~10,000 elements. There is no new test exercising this boundary. Something like:Without this, the regression could silently reappear if someone changes the dispatch again.
Self-hosted eval:
reversedependency confirmed safeThe new
map/filterinlib/reader/eval.slispcallreverse, which is a native builtin (line 334 ofeval.slisp). The approach is correct:foldaccumulates in reverse, then a singlereversepass gives O(n) behaviour without deep recursion. No issue here.lib/bootstrap.slispheader could be clearerThe file says it is a "HISTORICAL REFERENCE" but still contains live-looking SeqLisp code. The design doc already acknowledges the duplication problem (option 3: delete the file). If it stays, a more prominent note that this code is not evaluated anywhere would help avoid confusion for new contributors.
thenchain counts look correctdispatch-builtins: 15thens for 15 branches (cons/car/cdr/list/append/reverse/length/nth/last/take/drop/map/filter/fold/apply) ✓dispatch-predicates: 11thens for 11 branches (null?/number?/integer?/float?/string?/symbol?/list?/boolean?/equal?/gensym/not) ✓Positive notes
notsemantics are correct: only#fis falsy; numbers, nil, and other symbols are truthy. Consistent with the new test cases at predicates.slisp lines 43-48.nottests are well chosen (false, true, number, nil, symbol).bootstrap-envfromeval-print,run-file,run-repl, and the stdin path is consistently applied across botheval.seqandrepl.seq.Summary: Approve with the suggestion to add a large-list regression test and clarify the
lib/bootstrap.slispstatus. The empty-if idiom ineval-not-with-envis a minor style point, not a correctness problem.