general answer
-
look up āobject oriented programmingā, āseparation of concernsā, ācode reuseā and so on.
-
select SC class names and hit command+i
example
say i want to measure time between arbitrary events in sclang. i can make a variable and a function:
~now = nil;
~time = nil;
~tap = {
var thenow = SystemClock.seconds;
if (~now.notNil, {
~time = thenow - ~now;
~now = thenow;
}, {
~time = -1;
~now = thenow;
});
}
~measure_something = {
~tap.value;
postln(~time);
};
this is all well and good until i want to measure more than one thing. now i have to keep an array of times, and change the function signature to take an index into that array, or something. more generally, changes i make to the context in which iām using the timer code require me to change the timer code itself. maybe i will end up with copies of this code pasted all over with minor variants. undesirable for many reasons.
the more reusable way is to make a class; my variable and function become and field and a method:
Tapper {
var <>now, <>time;
*new {
^super.new.init;
}
init {
now = nil;
time = -1;
}
tap {
var thenow;
thenow = SystemClock.seconds;
if (now.notNil, {
time = thenow - now;
now = thenow;
}, {
time = -1;
now = thenow;
});
^time
}
}
and it is now trivial to safely reuse this code to make many timers to measure many different events:
n = 32;
~timers = Array.fill(32, { Tapper.new });
~handle_some_event = { arg which; postln(~timers[which].tap ); };
this is a dumb example, and classes can do a lot more (polymorphism, static state, &c), but that is one basic idea.
sclang has a big enough bag of tricks that you can actually roll your own OOP system with Events or something pretty easily, but Classes are the clean and efficient way (they are compiled to bytecode on sclang boot, and potentially execute much faster than interpreted sclang code.)