title:: Writing Classes summary:: Writing SuperCollider Classes categories:: Language>OOP related:: Reference/Classes For a basic tutorial on how standard object-orientated classes are composed, look elsewhere link::http://www.google.com/search?q=oop+class+tutorial:: note:: Class definitions are statically compiled when you launch SuperCollider or "recompile the library." This means that class definitions must be saved into a file with the extension .sc, in a disk location where SuperCollider looks for classes. Saving into the main class library (SCClassLibrary) is generally not recommended. It's preferable to use either the user or system extension directories. code:: Platform.userExtensionDir; // Extensions available only to your user account Platform.systemExtensionDir; // Extensions available to all users on the machine :: It is not possible to enter a class definition into an interpreter window and execute it. :: section:: Inheriting code:: MyClass : SomeSuperclass { } :: Without specifying a superclass, link::Classes/Object:: is assumed as the default superclass. code:: MyClass { // :Object is implied } :: section:: Methods class methods are specified with the asterisk within the class method, the keyword code::this:: refers to the class. A class in SuperCollider is itself an object. It is an instance of link::Classes/Class::. Instance methods are specified within the instance method, the keyword code::this:: refers to the instance. code:: MyClass { *classMethod { arg argument; } instanceMethod { arg argument; } } :: To return from the method use teletype::^:: (caret). Multiple exit points also possible. If no teletype::^:: is specified, the method will return the instance (and in the case of Class methods, will return the class). There is no such thing as returning void in SuperCollider. code:: MyClass { someMethod { ^returnObject } someOtherMethod { arg aBoolean; if(aBoolean,{ ^someObject },{ ^someOtherObject }) } } :: section:: New Instance creation code::Object.new:: will return to you a new object. When overriding the class method code::.new:: you must call the superclass, which in turn calls its superclass, up until code::Object.new:: is called and an object is actually created and its memory allocated. code:: MyClass { // this example adds no new functionality *new { ^super.new } // this is a normal constructor method *new1 { arg arga,argb,argc; ^super.new.init(arga,argb,argc) } init { arg arga,argb,argc; // do initiation here } } :: In this case note that code::super.new:: called the method new on the superclass and returned a new object. Subsequently we are calling the code::.init:: method on that object, which is an instance method. 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. :: One easy way to copy the arguments passed to the instance variables when creating a class is to use newCopyArgs. This method will copy the arguments to the instance variables in the order that the variables were defined in the class, starting the parent classes and working it's way down to the current class. code:: MyClass { var ::. code:: MyClass { var setMe, <>getMeOrSetMe; } :: you now have the methods: code:: someObject.getMe; someObject.setMe_(value); :: this also allows us to say: code:: someObject.setMe = value; someObject.getMeOrSetMe_(5); someObject.getMeOrSetMe.postln; :: A getter or setter method created in this fashion may be overridden in a subclass by manually writing the method setter methods should take only one argument to support both ways of expression consistently. eg. code:: MyClass { variable_ { arg newValue; variable = newValue.clip(minval,maxval); } } :: A setter method should always return the receiver. This is standard OOP practice (outside of SuperCollider as well). Do not return the new value from your setter. code:: MyClass { variable_ { arg newValue; myVariable = newValue; ^newValue // DO NOT DO THIS } } :: section:: External Method Files Methods may be added to Classes in separate files. This is equivalent to Categories in Objective-C. By convention, the file name starts with a lower case letter: the name of the method or feature that the methods are supporting. code:: + Class { newMethod { } *newClassMethod { } } :: section:: Slotted classes Classes defined with [slot] can use the syntax myClass[i] which will call myClass.at(i). This is useful when defining classes that inherit from a Collection type class. code:: MyClass[slot] { *new { ^super.new } at {|i| ("Index "++i).postln } } :: code:: a = MyClass(); a[3]; :: Defining a custom array of Points: code:: MyPointArray[slot] : RawArray { center { ^Point(*this.asArray.flop.collect{ |item| item.sum / item.size } ) } asArray{ ^this.collect{ |elem| elem.asArray } } } :: section:: Printing custom messages to post window By default when postln is called on an class instance the name of the class is printed in a post window. When code::postln:: or code::asString:: is called on a class instance, the class then calls code::printOn:: which can be overridden to obtain more useful information. code:: MyTestPoint { var