I've been reading through a lot of tutorials and forums on SuperCollider lately, and came accross on some code samples using *
and #
and _
, but I don't find why they are used ? Can someone explain that to me ? Is this related to avoiding multichannel expansion ?
Some samples:
(
var list = [1, 2, 3];
func(*list); // equivalent to func(list[0], list[1], list[2])
)
or
var a, b, c;
#a, b, c = [1, 2, 3]; // equivalent to a=1; b=2; c=3;
or
p = Pbind(
\degree, Pwhite(-7, 12, inf),
\dur, Pwrand([0.25, Pn(0.125, 2)], #[0.8, 0.2], inf),
\legato, Pfunc { ~legato } // retrieves value set by MIDI control
).play;
)
or (in the Pseq
)
(
Pbind(
\mtranspose, -1,
\octave, 5,
[\dur, \degree], Ptuple(y.collect(Pseq(_, inf)))
).play
)
Your sample quickly shows a summary of how this works, but let's expand it a bit and define a three argument function:
f = { arg a, b, c;
a + b + c;
};
When we want to call the function, we could do: f.value(1,1,1)
, which returns 3.
Now say for some reason we have an array of three numbers and we want to pass them to the function.
a = [1, 1, 1];
If we just try f.value(a)
we just an error. We could work around this by specifying f.value(a[0], a[1], a[2])
or we can use the * shortcut. This breaks up the array into a list for passing to a function. So the equivalent, shorter syntax is f.value(*a)
The pound/hash sign (whichever you call it) can to two different things, depending where it goes. Let's start with an array:
a = [1, 2, 3];
Let's say you have three variables and you want them to get the array contents. You could do:
b = a[0];
c = a[1];
d = a[2];
But that's a lot of typing, so an equivalent shortcut is
#b, c, d = a
The other meaning of # is when it comes right before the opening bracket of an array. According to Nick Collins:
A note about efficiency
You will occasionally see
#[1,2,3] //makes a totally fixed (non-dynamic) Array and is slightly cheaper, especially where you're not going to change the Array once you make it
rather than
[1,2,3] //a dynamic array
To show the difference
a= #[1,2,3];
a[0] //works
a[0] = 8 //fails, because it can't be changed
(from https://composerprogrammer.com/teaching/supercollider/sctutorial/Technicalities/02%20Arrays.html )
The underscore is doing something called Partial Application. It has a helpfile: https://doc.sccode.org/Reference/Partial-Application.html
What it's doing is replacing an argument declaration and usage. So in one of their examples, you could write:
(1..10).collect({ arg n; n.squared });
Or you could shorten it slightly:
(1..10).collect( _.squared );
So the _ is taking over declaring and using n. Note that the _ also means that you don't use the {}
brackets. In your example code, Ptuple(y.collect(Pseq(_, inf)))
could be rewritten as Ptuple(y.collect({arg z; Pseq(z, inf)}))
All of these shortcuts collectively are called "Syntactic Sugar". There's a helpfile called that, but if you're just learning SuperCollider, I suggest you avoid it for now and only dip in hen you come across a symbol doing something strange.