The Rub: to write classes in SuperCollider [SC] you need to give the file an extension of .sc and only have one or more class definitions in it. You'll also need to place the file in the SC extension folder which on a Mac is /Users/<your account>/Library/Application Support/SuperCollider/Extensions. You then need to recompile SC (Cmd + k) in order to see any changes you make. Yes, sad but true.

Constructors

Calling super.new will call the parent new of the current class always. So in the example, where each class inherits the one before it:

TestA {
    *new {
        "TestA *new called".postln;
    }
}

TestB : TestA {
    *new {
        super.new;
        "TestB *new called".postln;
    }
}

TestC : TestB {
    *new {
        super.new;
        "TestC *new called".postln;
    }
}

The output from running TestC.new will be:

TestA *new called
TestB *new called
TestC *new called
TestC

This is not the case with calling initialisation functions which, if given the same name will overwrite the parent function even if the called is proceded with super. (which is not such good OOP). The help says the following:

Warning: if the superclass also happened to call super.new.init it will have expected to call the .init method defined in that class (the superclass), but instead the message .init will find the implementation of the class that the object actually is, which is our new subclass. So you should use a unique method name like myclassinit if this is likely to be a problem.

So for example

TestA {
    *new {
        "TestA *new called".postln;
    }
    init {
        "TestA init called".postln;
    }
}

TestB : TestA {
    *new {
        super.new.init;
        "TestB *new called".postln;
    }
    init {
        super.init;
        "TestB init called".postln;
    }
}

Will not work as super only works on class (static) methods. One might expect this to work then, taking the advice of the Help documentation:

TestA {
    *new {
        "TestA *new called".postln;
        ^super.new.testAinit;
    }
    testAinit {
        "TestA init called".postln;
    }
}

TestB : TestA {
    *new {
        "TestB *new called".postln;
        ^super.new.testBinit;
    }
    testBinit {
        "TestB init called".postln;
    }
}

The result of TestB.new is the following:

TestB *new called
TestA *new called
TestA init called
TestB init called
a TestB

Note: I forgot to put the return symbol '^' in front of the super. and got the following, confusing, error:

TestB *new called
TestA *new called
TestA init called
ERROR: Message 'testBinit' not understood.
RECEIVER:
class TestB (23F5D2B0) {
  instance variables [19]
    name : Symbol 'TestB'
...

be warned!

Singleton

A Singleton is a classic object oriented design pattern that allows you to have one instance of a class shared all over the place. This is cleaner than using global variables and keeps the data with the functions that work on it.

Singleton { 
    classvar instance; 
    var someObject, someCollection, someOtherStuff; 

    *new { 
        | a,b,c | 
        ^super.newCopyArgs(a,b,c).init(); 
    } 

    *get { 
        ^( instance ?? { instance = Singleton.new })  // If it doesn't exist yet, create it.    
    } 

    init { 
        someObject = blah; 
        someCollection = .....; 
        someOtherStuff = ......; 
    } 

    *someMethod { 
        | ... args | 
        this.get.someMethod( *args ) 
    } 

    someMethod { } // actual implementation 

    *someOtherMethod { 
        | ... args | 
        this.get.someOtherMethod( *args ) 
    } 

    someOtherMethod { } 
}

This code was provided by Scott Carver who notes:

In this case, you can still do something simple like Singleton.someMethod(), but it's flexible enough that it can be changed down the road without breaking too much. Of course, the slightly better way would be:

  Singleton.get.someMethod() 

If you don't mind typing the extra four characters.

The real tick in the Singleton is seen here in the *get method. An instance of the class is instantiated only if one doesn't exist and is stored in the static class variable (which is essentially global), in this case instance. This instance is always returned thereafter and values can be stored in its properties.