Repository navigation
perf(js/ts): standard library one pass List.append builder - #5148
Open
shayanhabibi wants to merge 2 commits into
Open
shayanhabibi wants to merge 2 commits into
shayanhabibi wants to merge 2 commits into
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Source and proposed change
src/fable-library-ts/List.fsimplements append asfold (...) ys (reverse xs). Each nonempty left node is copied into a reversed intermediate list, then copied again into the result. Pythonfable_library/list.fsand DartList.fsuse the same reverse/fold append but are not in scope for me.Suggestion:
Semantic Proofs
What the compiler already knows
Full typed FCS context resolves the FSharp.Core ListModule.Append operation and immutable list types; no dynamic JS duck-typing test is needed.
Replacements.fs:2427–2453routes ListModule.Append through the generic List runtime call, whileReplacements.fs:1672–1674routes@directly to List.append. The measured reverse/fold implementation is therefore still on these call paths; neither route already emits the forward builder. The useful static guarantee is immutable list spine plus fresh, unpublished construction nodes, not purity of the element type. Element values may be mutable and remain shared. This supports a runtime fix benefiting compiler-recognized call sites without adding a new AST construct or per-element dispatch.Correctness and allocation
list-correctness.mjs: 48,337 successful assertions. Left lengths 0–150 crossed with right lengths 0, 1, 5, 50; output values, input nonmutation, element reference identity, exact right-tail identity, and empty-left identity checked. Instrumented actual FSharpList constructors confirm total node allocations of2n+1versusn+1for n=0,1,8,128,4096 (counts exclude input construction). This is allocation-count evidence, not measured bytes, retained heap, or GC time.No user callback is involved. Elements are copied as references and never compared, hashed, coerced, or enumerated individually; mutation of an element remains observable through both lists. Input nodes remain untouched. A fresh result prefix ends in the original right list, including the empty-left case. Valid F# immutable lists are the boundary: JS proxies or accessors replacing node fields, cyclic/corrupt lists, monkey-patched runtime functions, and allocation failure can observe different traversal/allocation behavior and are not covered. No .NET fixture or full compiler/test-suite run was performed for this experiment.
Timing
Windows, Node v26.7.0. Two exclusive runs; 9 alternating ABBA/BAAB blocks per case, 20 ms per sample, two samples per variant/block, 40 ms warmup per variant, explicit GC before blocks. Outputs escape to a global sink. Input generation excluded. Median paired candidate time change (negative is faster):
Absolute baseline times drifted between runs (e.g. n=128 about 2843 ns versus 5574 ns); do not present pooled ratios or precision estimates. Relative direction is strong for nonempty inputs; empty case is inconclusive. Microbenchmarks do not establish application or browser improvements. Runtime changes affect all JS/TS List.append calls and internal callers, with a small code surface but broad usage.
Warning
Before rollout we should test select applications, or save this for a pre-release