CheckBadValues should run on the first sample as well
[supercollider.git] / HelpSource / Guides / WritingClasses.schelp
blobb0fa613a7f030690e1580241bb01ee7f4f947c02
1 title:: Writing Classes
2 summary:: Writing SuperCollider Classes
3 categories:: Language>OOP
4 related:: Reference/Classes
6 For a basic tutorial on how standard object-orientated classes are composed, look elsewhere
7 link::http://www.google.com/search?q=oop+class+tutorial::
9 note:: Class definitions are statically compiled when you launch supercollider or "recompile the library." This means
10 that class definitions must be saved into a file with the extension .sc, in a disk location where supercollider looks
11 for classes. Saving into the main class library (SCClassLibrary) is generally not recommended. It's preferable to use
12 either the user or system extension directories.
14 code::
15 Platform.userExtensionDir;   // Extensions available only to your user account
16 Platform.systemExtensionDir; // Extensions available to all users on the machine
19 It is not possible to enter a class definition into an interpreter window and execute it.
24 section:: Inheriting
26 code::
27 MyClass : SomeSuperclass {
32 Without specifying a superclass, link::Classes/Object:: is assumed as the default superclass.
34 code::
35 MyClass { // :Object is implied
40 section:: Methods
42 class methods are specified with the asterix within the class method, the keyword code::this:: refers to the class. A
43 class in SuperCollider is itself an object.  It is an instance of link::Classes/Class::. Instance methods are specified
44 within the instance method, the keyword code::this:: refers to the instance.
46 code::
47 MyClass {
48     *classMethod { arg argument;
50     }
52     instanceMethod { arg argument;
54     }
59 To return from the method use teletype::^:: (caret). Multiple exit points also possible. If no teletype::^:: is
60 specified, the method will return the instance (and in the case of Class methods, will return the class). There is no
61 such thing as returning void in SuperCollider.
63 code::
64 MyClass {
65     someMethod {
66         ^returnObject
67     }
69     someOtherMethod { arg aBoolean;
70         if(aBoolean,{
71             ^someObject
72         },{
73             ^someOtherObject
74         })
75     }
81 section:: New Instance creation
83 code::Object.new:: will return to you a new object. When overriding the class method code::.new:: you must call the
84 superclass, which in turn calls its superclass, up until code::Object.new:: is called and an object is actually created
85 and its memory allocated.
87 code::
88 MyClass {
89     // this example adds no new functionality
90     *new {
91         ^super.new
92     }
94     // this is a normal constructor method
95     *new1 { arg arga,argb,argc;
96         ^super.new.init(arga,argb,argc)
97     }
98     init { arg arga,argb,argc;
99         // do initiation here
100     }
104 In this case note that code::super.new:: called the method new on the superclass and returned a new object. Subsequently
105 we are calling the code::.init:: method on that object, which is an instance method.
107 Warning:: If the superclass also happened to call super.new.init it will have expected to call the .init method defined
108 in that class (the superclass), but instead the message .init will find the implementation of the class that the object
109 actually is, which is our new subclass.  So you should use a unique method name like myclassinit if this is likely to be
110 a problem.
113 One easy way to copy the arguments passed to the instance variables when creating a class is to use newCopyArgs.  This
114 method will copy the arguments to the instance variables in the order that the variables were defined in the class,
115 starting the parent classes and working it's way down to the current class.
117 code::
118 MyClass {
119     var <a,b,c;
121     *new { arg a,b,c;
122         ^super.newCopyArgs(a,b,c)
123     }
126 MyChildClass : MyClass{
127     var <d;
129     *new { arg a,b,c,d;
130         ^super.newCopyArgs(a,b,c,d)
131     }
135 Over reliance on inheritance is usually a design flaw.  Explore "object composition" rather than trying to obtain all
136 your powers through inheritance. Is your "subclass" really some kind of "superclass" or are you just trying to swipe all
137 of daddy's methods? Do a websearch for Design Patterns.
139 Class variables are accessible within class methods and in any instance methods.
141 code::
142 MyClass {
143     classvar myClassvar;
144     var myInstanceVar;
148 For class initialization check code::initClass::.
150 section:: Overriding Methods (Overloading)
152 In order to change the behaviour of the superclass, often methods are overridden. Note that an object looks always for
153 the method it has defined first and then looks in the superclass. Here code::MyClass.value(2):: will return 6, not 4:
155 code::
156 Superclass {
157     calculate { arg in; in * 2 }
158     value { arg in; ^this.calculate(in) }
161 MyClass : Superclass {
162     calculate { arg in; in * 3 }
166 If the method of the superclass is needed, it can be called by super.
168 code::
169 Superclass {
170     var x;
172     init {
173         x = 5;
174     }
177 MyClass : Superclass {
178     var y;
179     init {
180         super.init;
181         y = 6;
182     }
188 section:: Getter Setter
190 SuperCollider demands that variables are not accessible outside of the class or instance. A method must be added to
191 explicitly give access:
193 code::
194 MyClass : Superclass {
195     var myVariable;
197     variable {
198         ^myVariable
199     }
201     variable_ { arg newValue;
202         myVariable = newValue;
203     }
207 These are referred to as getter and setter methods. SuperCollider allows these methods to be easily added by adding teletype::<:: or
208 teletype::>::.
210 code::
211 MyClass {
212     var <getMe, >setMe, <>getMeOrSetMe;
216 you now have the methods:
218 code::
219 someObject.getMe;
220 someObject.setMe_(value);
223 this also allows us to say:
225 code::
226 someObject.setMe = value;
228 someObject.getMeOrSetMe_(5);
229 someObject.getMeOrSetMe.postln;
233 A getter or setter method created in this fashion may be overridden in a subclass by manually writing the method setter
234 methods should take only one argument to support both ways of expression consistently.  eg.
236 code::
237 MyClass {
238     variable_ { arg newValue;
239         variable = newValue.clip(minval,maxval);
240     }
244 A setter method should always return the receiver. This is standard OOP practice (outside of SuperCollider as well). Do
245 not return the new value from your setter.
247 code::
248 MyClass {
249     variable_ { arg newValue;
250         myVariable = newValue;
251         ^newValue       // DO NOT DO THIS
252     }
256 section:: External Method Files
258 Methods may be added to Classes in separate files.  This is equivalent to Protocols in Objective-C.  By convention, the
259 file name starts with a lower case letter: the name of the method or feature that the methods are supporting.
261 code::
262 + Class {
263     newMethod {
264     }
266     *newClassMethod {
267     }
272 section:: Slotted classes
274 Classes defined with [slot] can use the syntax myClass[i] which will call myClass.at(i). This is usefull when defining
275 classes that inherit from a Collection type class.
277 code::
278 MyClass[slot] {
279     *new {
280          ^super.new
281     }
283     at {|i|
284         ("Index "++i).postln
285     }
289 code::
290 a = MyClass();
291 a[3];
294 Defining a custom array of Points:
296 code::
297 MyPointArray[slot] : RawArray {
298     center { ^Point(*this.asArray.flop.collect{ |item| item.sum / item.size } ) }
299     asArray{ ^this.collect{ |elem| elem.asArray } }
304 section:: Printing custom messages to post window
306 By default when postln is called on an class instance the name of the class is printed in a post window. When
307 code::postln:: or code::asString:: is called on a class instance, the class then calls code::printOn:: which can be
308 overridden to obtain more useful information.
310 code::
311 MyTestPoint {
312     var <x, <y;
314     *new{ |x,y| ^super.newCopyArgs(x,y) }
316     printOn { arg stream;
317         stream << "MyTestPoint( " << x << ", " << y << " )";
318     }
322 code::
323 a = MyTestPoint(2,3);
326 subsection:: Defining custom asCompileString behaviour
328 A call to code::asCompileString:: should return a string which when evaluated creates the exact same instance of the
329 class. To define a custom behaviour one should either override code::storeOn:: or code::storeArgs::. The method
330 code::storeOn:: should return the string that evaluated creates the instance of the current object. The method
331 code::storeArgs:: should return an array with the arguments to be passed to code::TheClass.new::. In most cases this
332 method can be used instead of code::storeOn::.
334 code::
335 // either
336 MyTestPoint {
337     var <x, <y;
339     *new{ |x,y| ^super.newCopyArgs(x,y) }
341     storeOn { arg stream;
342         stream << "MyTestPoint.new(" << x << ", " << y << ")";
343     }
346 // or
347 MyTestPoint {
348     var <x, <y;
350     *new{ |x,y| ^super.newCopyArgs(x,y) }
352     storeArgs { arg stream;
353         ^[x,y]
354     }
358 code::
359 MyTestPoint(2,3).asCompileString;
362 section:: Catching methods that are not explicitly defined
364 It is possible to catch calls to methods that are not explicitly defined in a Class by overriding code::doesNotUnderstand::.
366 code::
367 MyClass {
368     *new { ^super.new }
370     doesNotUnderstand { arg selector...args;
371         (this.class++" does not understand method "++selector);
373         If(UGen.findRespondingMethodFor(selector).notNil){
374             "But UGen understands this method".postln
375         };
376     }
380 code::
381 a = MyClass();
382 a.someMethodThatDoesNotExist
385 section:: Tricks and Traps
387 definitionList::
389 ## "Superclass not found..."
391 || In one given code file, you can only put classes that inherit from each Object, each other, and one external class.
392 In other words, you can't inherit from two separate classes that are defined in separate files.
394 If you should happen to declare a variable in a subclass and use the same name as a variable declared in a superclass,
395 you will find that both variables exist, but only the one in the object's actual class is accessible.  You should not do
396 that. This will at some point become an error worthy of compilation failure.