Writing SuperCollider code like Javascript

Keep your code in its own name space. Here's a little trick I picked up from Alberto de Campo

q = q ? ();

This checks to see if the q variable is already allocated (i.e. by yourself in other code that begins like this), if it is then it does nothing otherwise it makes it a dictionary in which you can stuff your own variables without having to use the global environment (i.e. with variables that begin with ~).

We use the q variable because it is already initialised by SuperCollider in the global environment, i.e. we don't have to go var q when we execute our scripts every time.

NOte on Global variables

In most programming languages global variables are considered baaaaad because:

  • You can run into conflicts if you use it with other code that might also use the same names for variables.
  • In most coding languages you have the concept of encapsulation which means that little chunks of code should not affect any other code outside of themselves. Globals are like having a wire hanging out of your stereo which lets you tune the radio: its ugly.

Once you have that setup you can start to fill up your q "namespace" (ie. a named space for your code) with your own variables:

q.year = 1965;
q.thunder = { "Speaks to lightning".postln };   // function
q.favourateThings = [ "Raindrops on roses", "whiskers on kittens" ]; // Array

and so on. This is actually very similar to the way JavaScript handles name spacing. You might even prefer this way of organising your code to using classes since you:

  • Don't have to put them in a certain folder, you can keep it with the other related code.
  • Don't have to recompile SuperCollider for every change you make (and thus don't risk SC not starting again/crashing/etc) which is slow and tedious.

Classes in SC are kind-of a pain in the ass compared to other languages.

Alternatively

To be even more Javascript you could rewrite the above like so:

q.austrian = (
    year: 1965,

    favourateThings: [ "Bright copper kettles", "warm woolen mittens" ],

    thunder: { "Speaks to lightning".postln },

    scaredOfLightning: { | self, weAreScared |  
        if( weAreScared ) {
            self.favourateThings.do { |thing| thing.postln }
        };
        "..these are a few of my favourtate things"
    } 
);

Here I've made a sub-namespace in the q name space called austrian, which is just a dictionary inside a dictionary, and initialised it with our variables and functions. Once this is initialised we can use it like so:

q.austrian.scaredOfLightning(true)

We can go as many levels deep as we like and this means if we make libraries that also use the q variable/namespace they won't write over each other.

Also note we're using colons : instead of equal signs = to assign things to their label in the dictionary and separating them all with commas ,. This makes it look more like a Class declaration.

Note

When adding functions to the variable like this you get 2 changes in behavior:

  • You don't have to use the .value() method to evaluate the function i.e. myCoolFunction.value("argument"), you can just use the brackets q.myCoolFunction("argument"). YAY!
  • The first argument the function will receive is the object itself (in our examples q), then the arguments you pass in. I wouldn't even know where to start looking for this in the SC documentation. If your familiar with Python then you'd be used to this. So your function definition would look something like:

    q.myCoolFunction = { arg self, something; ... }
    

    where self ends up being q in this case.