Functions can take parameters, which can be positional or named. Normally "positional" ones start at $1 for the first parameter to a function. Since a function can be an element of an array, they too can take parameters just like one a global (or local) function. This all works fine (with correct bracing).
But when the function is run from the array using [($array->"fn") hello], the parameter "hello" is at $0, not the expected $1. With multiple parameters, what would be $2 at global scoped function, is $1 when function is defined within an array. Basically, whether the first argument is $0 or $1, depends on where it lives. Even mixin a named parameter still works, the positional arguments are just shifted by one and key=value ones work anywhere as usual.
I'd say it's a bug, but more subtle than that. But I can see the logic: An array function is more like anonymous function is CS terms, while global function is a command (commands have name, a name is an argument) – so the first argument known to the function is always $0, which could be it's name if available.
However, this logic was quite subtle to figure out since I couldn't tell why the same function acted differently when cut-and-pasting code from a global to array – I didn't notice they were just shift: they just looked wrong/old/sometime and obviously cause code that expected a $1="yes" not $1=nil. Fix was simple: use $0 when a function is defined in an array.
I think this shows the issue I ran into (although more obvious in the example than in real scripts):
Code: Select all
:global hello
:set $hello do={:put "$0 $1"}
$hello world
#>> $hello world
:global greetings [toarray ""]
:set ($greetings->"hello") do={:put "hello $1 "}
[($greetings->"hello") world]
#>> hello
{ /terminal style error; put "expected: 'hello world' not just 'hello' string"; /terminal style none }
# use $0 instead, works:
:set ($greetings->"hello") do={:put "hello $0"}
[($greetings->"hello") world]
#>> hello world