inheritancesupercollider

SuperCollider inheritance


I've got some simple inheritance in SuperCollider.

But the order of execution seems wrong??

MooRoot : MooPlayer {

    var <api, <moo;

    *new { |moo, name|
        "MooRoot new %".format(name).postln;

        ^super.new.init(moo, name);
    }

    init {|imoo, name|

        super.init();
        "MooRoot init %".format(name).postln;
    }

}

MooPlayer {
    var contents, ownedObjects, <>user, <me, <permissions;


    *new {
        ^super.new.init;
    }

    init {
    }


}

When I call MooRoot(1, "Jessie");, the output looks like:

MooRoot new Jessie
MooRoot init nil
MooRoot init Jessie
-> a MooRoot

It invokes the init method twice, once with nil arguments. This seems wildly wrong, but I can't see what mistake I've made. How can I force it to only call init one time with the correct arguments?


Solution

  • This turns out to be directly addressed in the help documentation: https://doc.sccode.org/Guides/WritingClasses.html#Instances

    The answer is to not keep using the init method name, but to have a different name for every subclass.

    Eg

    MooRoot : MooPlayer {
    
        var <api, <moo;
    
        *new { |moo, name, me|
            "MooRoot new %".format(name).postln;
    
            ^super.new(me).initRoot(moo, name);
        }
    
        initRoot {|imoo, name|
    
            "MooRoot init %".format(name).postln;
        }
    
    }
    
    MooPlayer {
        var contents, ownedObjects, <>user, <me, <permissions;
    
    
        *new {|me|
            ^super.new.init(me);
        }
    
        init {|i_me|
            me = i_me;
        }
    
    
    }
    

    In this version, we have three arguments to the subclass's new message, one of which is dealt with by the superclass. To pass that up to the superclass, we pass this as an argument to super.new.

    The other things happen is now: MoorRoot.new, then MooPlayer.new, then MooPlayer.init, then MooRoot.initRoot