Drop the upper bound on user-defined function arity - #171
Merged
Merged
Conversation
object.Function.Evaluate (the path list.map/filter/reduce/each/sort call a callback through) never enforced a maximum, so a callback like (item) => item * 2 already worked as a map argument even though map also passes an index - only because that path skipped arity checking entirely. Requiring a direct call to declare every trailing parameter a function doesn't use fought that existing convention instead of matching it. Extra arguments are now dropped for every user-defined function, the same way Evaluate already dropped them; the minimum-argument check stays.
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.
Overview
Arity checking for user-defined functions (§14 decision 1) was stricter than the interpreter's own callback path.
object.Function.Evaluate— whatlist.map/filter/reduce/each/sortcall a callback through — never enforced a maximum argument count, so a callback like(item) => item * 2already worked asmap's argument even thoughmapalso passes an index and Ghost's own callers depend on this being fine. A direct call, though, was rejected for passing more arguments than a function declared parameters for, which meant a function could only rely on that permissiveness by accident of which call path invoked it, rather than as a rule of the language. This surfaced while updating Lumen, whose callbacks only survived because of that undocumented divergence between the two paths.The minimum-argument check is unchanged: a call that leaves a required parameter unbound is still an
Argumentfault.Changes
Changed
evaluator/function.go'scheckArityno longer rejects a call for supplying more arguments than a function declares parameters for — only a missing required argument is an error now, checked withobject.ArityAtLeastin every case.SPEC.md(§8.7 and §14 decision 1) to describe and justify the revised behavior, and the §12 checklist entry that referenced "strict arity checking."Removed
Fixed
Related issues
Additional context
Updated
evaluator/evaluator_test.go:TestFunctionArity's exact/range-arity cases now expect the "at least" wording, andTestFunctionArityAllowsDefaultsAndVarietygained cases confirming extra arguments are accepted and dropped rather than rejected.go build ./...andgo test ./...are clean.Generated by Claude Code