How do I define a function which gets some positional arguments and a whole rest of arguments. This is not working:
(
{arg x, ...rest; [x, rest].postln}.(1,2,3,4,5)
)
I had expected it to answer [1, [2, 3, 4, 5]]
How do I define a function which gets some positional arguments and a whole rest of arguments. This is not working:
(
{arg x, ...rest; [x, rest].postln}.(1,2,3,4,5)
)
I had expected it to answer [1, [2, 3, 4, 5]]
Because the ...
is already a separator between tokens, the comma would be redundant and should be left out.
(
{ arg x ... rest; [x, rest].postln }.(1,2,3,4,5)
)
I was looking for where this is documented and⦠canāt find it just nowā¦
EDIT: OK, yeah, this is confusing: āIf the last argument in the list is preceded by three dots (an ellipsis), then all the remaining arguments that were passed will be assigned to that variable as an Array. Arguments must be separated by commasā when itās really āArguments must be separated by commas except when using ...
ā ā Like in your writing classes in school, āA paragraph should have only one topic sentenceā ā this one switches topics and led to a wrong conclusion that ā,ā is required for ...
args.
So maybe change like this:
Arguments must be separated by commas.**
If the last argument in the list is preceded by three dots (an ellipsis), then all the remaining arguments that were passed will be assigned to that variable as an Array. In this case only, the comma should be omitted.
** (Except that isnāt true either: { |x 1 y 2| [x, y].postln }.value
)
hjh
⦠and `{| a b ⦠args| } doesnāt need commas either!
how about:
An argument list immediately follows the open curly bracket of a function definition. An argument list either begins with the reserved word
arg
, or is contained between two vertical bars. When using the āargā style arguments must be separated by commas, when using vertical bars (āpipe modeā) commas are optional.
[ ⦠]
If the last argument in the list is preceded by three dots (an ellipsis), then all the remaining arguments that were passed will be assigned to that variable as an Array. Ellipses should not be preceded by a comma.
Slightly off topicā¦
Was just looking at the bison file to see how this was defined and realised a whole bunch of stuff.
This is all validā¦
Modify existing (right to left) arguments
{
|foo(#car, bar = gar.collect(_+1)), bar, car ...gar|
[foo, bar, car, gar].postln
}.(gar: [1,2,3]) // [ [ 2, 3, 4 ], 3, 2, [ 1, 2, 3 ] ]
Thowing if an arg isnāt set (perhaps legitimately useful?)
~foo = {
|a( Error("arg not set").throw )|
a + 1
};
~foo.(); // throws
~foo.(1); // 2
Mutating globals.
~c = 10;
~m = { var out = ~c; ~c = ~c - 1; out };
~a = { |a( ~m.() )| a };
~a.() // 10
~a.() // 9
~a.() // 8
....
Multiple expressions and blocking.
~a = {
|a( 1.wait; \bar )|
a.postln
}
Any valid expression can go in there, including, my favouriteā¦
{ |head(thisFunction.value)| }.() // (this will crash the interpreter)
Also, when using pipes (which is called slotdef in the code) there can can only have literals after the equals sign but any expression in brackets, whereas with arg
you can have any expression after the equals.
ok this is nuts - can you walk me through this? when did car get set to 2?
If thereās arg a = expression
or | a(expression) |
, it compiles the same as arg a = nil; a !? { a = expression }
.
So this example is really:
{
|foo, bar, car ...gar|
foo !? { foo = (#car, bar = gar.collect(_+1)) };
[foo, bar, car, gar].postln
}.(gar: [1,2,3]);
EDIT: I forgot the variable reassignment initially, fixed.
Iāve doubts about readability but itās interesting that it can be pushed this far.
hjh
Yeah, the arg list syntax and semantics are pretty crusty when you consider all the cases I donāt think anyone makes too significant use of it.
This is one of the more delightfully weird corners of the sclang syntax. But, consider that this partly what saves us from the fate of Python, where the default values for function arguments are actually globals that can be mutatedā¦
As soon as you can have any default that isnāt a literal (essential for sclang because lots of basic things arenāt literalsā¦), youāre a bit stuck allowing any expression as a default and executing it more or less like this - or, disallowing āweirdā cases in semi-arbitrary ways. I think the semantics and allowances here are pretty close to C++, except in C++ the defaults are evaluated at the call site so the other arguments arenāt in scope to use / mutate.
It used to be possible to mutate String literal argument defaults until we made String literals immutable to fix that
hjh