SuperCollider functions are curly-brace blocks that run only when sent .value and return their last expression
In SuperCollider, any expression inside curly braces {} is a function object: code that is not executed until it is explicitly called. Sending .value runs the block and returns the value of its last expression. Arguments are declared at the top of the body with the arg keyword — {arg a, b; a + b} — or with pipe notation {|a, b| a + b}, and are supplied as f.value(3, 7). Functions enable reuse: the same recipe applies to different inputs. They are also the building block of SynthDefs, conditionals, and iterators. A key consequence of deferred evaluation: a function containing randomness generates fresh values each call, unlike a random number assigned once to a variable. Thus rand(1000.0).dup(5) duplicates one number five times, whereas {rand(1000.0)}.dup(5) executes the pick five separate times, giving five different numbers.
Examples
f = {arg a, b; a + b};
f.value(3, 7); // => 10
f = {|a, b| [a+b, a*b]};
~myRand = {rrand(0, 10)};
~myRand.value; // different number each call
rand(1000.0).dup(5); // same number 5 times
{rand(1000.0)}.dup(5); // 5 different numbers
Assessment
Predict and verify the difference between Array.fill(5, rrand(0,10)) and Array.fill(5, {rrand(0,10)}). Write a function taking a MIDI note number and returning its frequency in Hz (and, optionally, its nearest octave number).