Inheritance inits

[This is x-posted to stack overflow SuperCollider inheritance - Stack Overflow ]

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?

This is actually addresses in the help documents. Writing Classes | SuperCollider 3.12.2 Help

The problem is using the method name init over and over. If I rename it for subclasses, I’ll be fine.

Better is to avoid using init methods where possible and put all the logic into the constructor before you actually make the object. Most of the time, you can initialise the members and after construct them into an object.

1 Like

Might be good to give this recommendation and an example in the Writing Classes helpfile?

1 Like

See also this thread: Writing Classes: init & new clarification needed - #5 by Eric_Sluyter

@jordan does newCopyArgs work with keys in latest dev branch?

It’s ready to merge.

Once this little fix for superPerformArgs is merged to.

you will be able to do this clever pattern that python does…


Base {
   var a, b;
   *new { | a, b ...args, kwargs| 
       // Something with a and b
       ^superPerformArgs(\newCopyArgs, [a, b] ++ args, kwargs)
   }
}

Child: Base {
   var c, d;
   *new { |...args, kwargs|
      // See if c or d was passed and do something with them.
      ^superPerformArgs(\new, args, kwargs)
   }
}

Now you can call it like this…

Child(a: 1, b: 2, d: 4) // leaving c at nil

Just to answer this thread directly, you only need init methods when you must initialise ‘a’ and ‘b’ before ‘c’ and ‘d’. Generally that coupling is best avoided, but occasionally it is needed and init methods are one way to do it. It’s just they are very powerful but hard to manage at scale, particularly when you have multiple constructors and deep inheritance trees - its like use a jack hammer to open a bottle, only occasionally necessary.

1 Like