Skip to content

Drop the upper bound on user-defined function arity - #171

Merged
kaidesu merged 1 commit into
1.0from
claude/arity-checking-strictness-lc5na4
Aug 30, 2026
Merged

kaidesu merged 1 commit into
1.0from
claude/arity-checking-strictness-lc5na4

Conversation

@kaidesu

@kaidesu kaidesu commented Aug 30, 2026

Copy link
Copy Markdown
Member

Overview

Arity checking for user-defined functions (§14 decision 1) was stricter than the interpreter's own callback path. object.Function.Evaluate — what list.map/filter/reduce/each/sort call a callback through — never enforced a maximum argument count, so a callback like (item) => item * 2 already worked as map's argument even though map also 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.

function greet(name) { return `hi ${name}` }
greet("Ada", "extra")   // before: argument error - `greet()` expects 1 argument, got 2
                        // after:  "hi Ada"

[1, 2, 3].map((item) => item * 2)   // already worked before (via list.map's own call path);
                                    // now the same holds for a direct call, too

The minimum-argument check is unchanged: a call that leaves a required parameter unbound is still an Argument fault.

Changes

Changed

  • evaluator/function.go's checkArity no longer rejects a call for supplying more arguments than a function declares parameters for — only a missing required argument is an error now, checked with object.ArityAtLeast in every case.
  • Updated 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, and TestFunctionArityAllowsDefaultsAndVariety gained cases confirming extra arguments are accepted and dropped rather than rejected. go build ./... and go test ./... are clean.


Generated by Claude Code

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.
@kaidesu
kaidesu marked this pull request as ready for review August 30, 2026 09:11
@kaidesu
kaidesu merged commit 185f785 into 1.0 Aug 30, 2026
2 checks passed
@kaidesu
kaidesu deleted the claude/arity-checking-strictness-lc5na4 branch August 30, 2026 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants