1 <!DOCTYPE html PUBLIC
"-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
4 <meta http-equiv=
"Content-Type" content=
"text/html; charset=UTF-8">
5 <meta http-equiv=
"Content-Style-Type" content=
"text/css">
7 <meta name=
"Generator" content=
"Cocoa HTML Writer">
8 <meta name=
"CocoaVersion" content=
"824.42">
9 <style type=
"text/css">
10 p
.p1
{margin: 0.0px 0.0px 0.0px 0.0px; font: 20.0px Helvetica
}
11 p
.p2
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica
; min-height: 14.0px}
12 p
.p3
{margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica
}
13 p
.p4
{margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px Helvetica
}
14 p
.p5
{margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco
; color: #a71e12}
15 p
.p6
{margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco
; color: #a71e12; min-height: 12.0px}
16 p
.p7
{margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco
}
17 p
.p8
{margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco
; color: #0019b7}
18 p
.p9
{margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco
; min-height: 12.0px}
19 p
.p10
{margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco
; color: #606060}
20 span
.s1
{color: #000000}
21 span
.s2
{color: #0019b7}
22 span
.s3
{color: #a71e12}
23 span
.s4
{color: #606060}
24 span
.s5
{color: #326f17}
25 span
.Apple-tab-span
{white-space:pre
}
29 <p class=
"p1"><b>Understanding errors
<span class=
"Apple-converted-space"> </span></b></p>
30 <p class=
"p2"><br></p>
31 <p class=
"p3"><b>1. Reading error dumps
</b></p>
32 <p class=
"p3"><b>2. Error objects and error handling
</b></p>
33 <p class=
"p3"><b>3. Common primitive errors
</b></p>
34 <p class=
"p3"><b>4. A common network error
</b></p>
35 <p class=
"p3"><b>5. A common warning
</b></p>
36 <p class=
"p2"><br></p>
37 <p class=
"p4"><b>1. Reading error dumps
<span class=
"Apple-converted-space"> </span></b></p>
38 <p class=
"p2"><br></p>
39 <p class=
"p3">When sc3 reports an error to the user, there are usually three parts:
<span class=
"Apple-converted-space"> </span></p>
40 <p class=
"p2"><br></p>
41 <p class=
"p3">- the error text
</p>
42 <p class=
"p3">- a dump of the receiver of the method that caused the error, and/or any arguments of the method call
</p>
43 <p class=
"p3">- a dump of the call stack to the point of the error
<span class=
"Apple-converted-space"> </span></p>
44 <p class=
"p2"><br></p>
45 <p class=
"p3">For example:
</p>
46 <p class=
"p2"><br></p>
47 <p class=
"p5"><span class=
"s1">1.blech
<span class=
"Apple-converted-space"> </span></span>// no class implements this method; therefore you'll get an error
</p>
48 <p class=
"p6"><br></p>
49 <p class=
"p5">// error text
</p>
50 <p class=
"p7">ERROR: Message 'blech' not understood.
</p>
51 <p class=
"p5">// receiver and args
</p>
52 <p class=
"p7">RECEIVER:
</p>
53 <p class=
"p7"><span class=
"Apple-converted-space"> </span>Integer
1</p>
54 <p class=
"p7">ARGS:
</p>
55 <p class=
"p7">Instance of Array {
<span class=
"Apple-converted-space"> </span>(
02207560, gc=
01, fmt=
01, flg=
11, set=
00)
</p>
56 <p class=
"p7"><span class=
"Apple-converted-space"> </span>indexed slots [
0]
</p>
58 <p class=
"p5">// call stack
</p>
59 <p class=
"p7">CALL STACK:
</p>
60 <p class=
"p7"><span class=
"Apple-tab-span"> </span>DoesNotUnderstandError-reportError
</p>
61 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of DoesNotUnderstandError
></p>
62 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Nil-handleError
</p>
63 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this = nil
</p>
64 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg error =
<instance of DoesNotUnderstandError
></p>
65 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Object-throw
</p>
66 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of DoesNotUnderstandError
></p>
67 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Object-doesNotUnderstand
</p>
68 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
1</p>
69 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg selector = 'blech'
</p>
70 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg args = [*
0]
</p>
71 <p class=
"p7"><span class=
"Apple-tab-span"> </span>< closed FunctionDef
><span class=
"Apple-converted-space"> </span>(no arguments or variables)
</p>
72 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Interpreter-interpretPrintCmdLine
</p>
73 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of Interpreter
></p>
74 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>var res = nil
</p>
75 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>var func =
<instance of Function
></p>
76 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Process-interpretPrintCmdLine
</p>
77 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of Main
></p>
78 <p class=
"p2"><br></p>
79 <p class=
"p3">Each of these parts provides valuable information about the cause of the error. Debugging is much easier if you understand what the error output means.
<span class=
"Apple-converted-space"> </span></p>
80 <p class=
"p2"><br></p>
81 <p class=
"p3"><b>Error text:
</b> A string describing the error. In this case,
"Message 'xxx' not understood" means that you attempted to use the method xxx on a class that does not implement it.
<span class=
"Apple-converted-space"> </span></p>
82 <p class=
"p2"><br></p>
83 <p class=
"p3"><b>Receiver and arguments:
</b> The method was applied to an integer (
1), with no arguments (the size of the arguments array is
0).
<span class=
"Apple-converted-space"> </span></p>
84 <p class=
"p2"><br></p>
85 <p class=
"p3"><b>Call stack:
</b> Order of execution in the call stack is in reverse: the top of the stack shows the most recent calls.
<span class=
"Apple-converted-space"> </span></p>
86 <p class=
"p2"><br></p>
87 <p class=
"p3">Most call stacks for errors will show the same top three calls as shown here (calling the method reportError on an error class, calling handleError on Nil, and calling throw on the error object). You can ignore these three calls.
<span class=
"Apple-converted-space"> </span></p>
88 <p class=
"p2"><br></p>
89 <p class=
"p3">Following is the meat: the error happened when an object was not understood. Continuing to read down, it happened inside a function definition. (Every time you highlight a block of code and press the enter key, the code is compiled into a function definition and executed. So, this function definition simply refers to the text submitted to the interpreter.) And, it all began with the instruction to interpret and print a command line.
<span class=
"Apple-converted-space"> </span></p>
90 <p class=
"p2"><br></p>
91 <p class=
"p3">Here is a slightly more complex example, showing how you can use the variables listed for each call in the call stack to help locate the error.
</p>
92 <p class=
"p2"><br></p>
93 <p class=
"p8">Routine
<span class=
"s1">({
</span></p>
94 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"s2">var
</span> a;
</p>
95 <p class=
"p7"><span class=
"Apple-tab-span"> </span>a =
5;
</p>
96 <p class=
"p7"><span class=
"Apple-tab-span"> </span>loop {
</p>
97 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"s2">var
</span> b;
</p>
98 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>b =
20.rand;
</p>
99 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>b.postln.ecky_ecky_phtang;
<span class=
"Apple-converted-space"> </span><span class=
"s3">//
"NI!!!!"</span></p>
100 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>a.wait;
</p>
101 <p class=
"p7"><span class=
"Apple-tab-span"> </span>}
</p>
102 <p class=
"p7">}).play;
</p>
103 <p class=
"p2"><br></p>
104 <p class=
"p7">ERROR: Message 'ecky_ecky_phtang' not understood.
</p>
105 <p class=
"p7">RECEIVER:
</p>
106 <p class=
"p7"><span class=
"Apple-converted-space"> </span>Integer
6</p>
107 <p class=
"p7">ARGS:
</p>
108 <p class=
"p7">Instance of Array {
<span class=
"Apple-converted-space"> </span>(
02207560, gc=
01, fmt=
01, flg=
11, set=
00)
</p>
109 <p class=
"p7"><span class=
"Apple-converted-space"> </span>indexed slots [
0]
</p>
111 <p class=
"p7">CALL STACK:
</p>
112 <p class=
"p7"><span class=
"Apple-tab-span"> </span>DoesNotUnderstandError-reportError
</p>
113 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of DoesNotUnderstandError
></p>
114 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Nil-handleError
</p>
115 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this = nil
</p>
116 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg error =
<instance of DoesNotUnderstandError
></p>
117 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Object-throw
</p>
118 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of DoesNotUnderstandError
></p>
119 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Object-doesNotUnderstand
</p>
120 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
6</p>
121 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg selector = 'ecky_ecky_phtang'
</p>
122 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg args = [*
0]
</p>
123 <p class=
"p7"><span class=
"Apple-tab-span"> </span>< FunctionDef in closed FunctionDef
></p>
124 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>var b =
6</p>
125 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Function-loop
</p>
126 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of Function
></p>
127 <p class=
"p7"><span class=
"Apple-tab-span"> </span>< FunctionDef in closed FunctionDef
></p>
128 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>var a =
5</p>
129 <p class=
"p7"><span class=
"Apple-tab-span"> </span>Routine-prStart
</p>
130 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of Routine
></p>
131 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg inval =
1542.075067</p>
132 <p class=
"p9"><br></p>
133 <p class=
"p3">Reading from the bottom this time, to trace the flow in chronological order: this time, execution did not begin with the command line, but with a routine commencing within the scheduler (Routine({...}).play). Note that there are two calls identified as
"FunctionDef in closed FunctionDef" and that they can be distinguished by the variables contained within. The earlier call (second from the bottom) defines the variable
"a" while the other defines
"b." To locate the error in the code, then, you should look for a function defining the variable
"b" that is
<i>called
</i> within another function defining
"a" inside a routine.
<span class=
"Apple-converted-space"> </span></p>
134 <p class=
"p2"><br></p>
135 <p class=
"p3">What if the error occurred not inside a function definition that you wrote, but inside a method in the class library? There may be a bug in the method, or you may have thought the method took a certain kind of argument when in fact it expects something else.
<span class=
"Apple-converted-space"> </span></p>
136 <p class=
"p2"><br></p>
137 <p class=
"p3">If you double click on the construction
"ClassName-methodName" in the call stack, the whole thing is selected. Then you can press cmd-J to open the method definition and look at the source code.
</p>
138 <p class=
"p2"><br></p>
139 <p class=
"p4"><b>2. Error objects and error handling
<span class=
"Apple-converted-space"> </span></b></p>
140 <p class=
"p2"><br></p>
141 <p class=
"p3">sc3 implements error reporting using Error objects, which are instances of the class Error or one of its subclasses. Any code (whether in the class library or any user application) can throw an error any time as follows:
<span class=
"Apple-converted-space"> </span></p>
142 <p class=
"p2"><br></p>
143 <p class=
"p10"><span class=
"s2">Error
</span><span class=
"s1">(
</span>"This is a basic error."<span class=
"s1">).throw;
<span class=
"Apple-converted-space"> </span></span></p>
144 <p class=
"p2"><br></p>
145 <p class=
"p3">You can also catch exceptions that occur within functions by executing the function with
"try" or
"protect" instead of
"value."</p>
146 <p class=
"p2"><br></p>
147 <p class=
"p3"><b>try -
</b> execute the first function. On an error, execute the second function and suppress the error. The second function can rethrow the error if desired, allowing you to decide which errors will be reported and which suppressed. In this example, we do not rethrow the error, so the error is swallowed and execution continues to the end.
</p>
148 <p class=
"p2"><br></p>
149 <p class=
"p7">try {
1.blech } {
<span class=
"s2">|error|
</span> <span class=
"s4">"oops"</span>.postln };
</p>
150 <p class=
"p10">"next line"<span class=
"s1">.postln;
</span></p>
151 <p class=
"p2"><br></p>
152 <p class=
"p7">oops
</p>
153 <p class=
"p7">next line
</p>
154 <p class=
"p2"><br></p>
155 <p class=
"p3"><b>protect -
</b> executes the first function. On an error, execute the second function before reporting the error. This is useful when the steps before the protect make some changes that need to be undone if an error occurs. See the method Environment-use for an example.
</p>
156 <p class=
"p2"><br></p>
157 <p class=
"p7">protect {
1.blech } {
<span class=
"s2">|error|
</span> <span class=
"s4">"oops"</span>.postln };
</p>
158 <p class=
"p10">"next line"<span class=
"s1">.postln;
</span></p>
159 <p class=
"p2"><br></p>
160 <p class=
"p5"><span class=
"s1">oops
<span class=
"Apple-converted-space"> </span></span>// without protect, this would not be posted
</p>
161 <p class=
"p7">ERROR: Message 'blech' not understood.
</p>
162 <p class=
"p7">RECEIVER:
</p>
163 <p class=
"p7"><span class=
"Apple-converted-space"> </span>Integer
1</p>
164 <p class=
"p7">ARGS:
</p>
165 <p class=
"p7">Instance of Array {
<span class=
"Apple-converted-space"> </span>(
02207560, gc=
01, fmt=
01, flg=
11, set=
00)
</p>
166 <p class=
"p7"><span class=
"Apple-converted-space"> </span>indexed slots [
0]
</p>
168 <p class=
"p7">CALL STACK:
</p>
169 <p class=
"p7"><span class=
"Apple-tab-span"> </span>DoesNotUnderstandError-reportError
</p>
170 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span>arg this =
<instance of DoesNotUnderstandError
></p>
171 <p class=
"p2"><br></p>
172 <p class=
"p2"><br></p>
173 <p class=
"p3">Prior to August
2004, try and protect do not return the value of the function to the caller if there is no error.
</p>
174 <p class=
"p2"><br></p>
175 <p class=
"p7">try {
1+
1 }
</p>
176 <p class=
"p9"><br></p>
177 <p class=
"p7">a Function
</p>
178 <p class=
"p2"><br></p>
179 <p class=
"p3">More recent builds (since early August
2004) do return the function's value. Non-error objects can be thrown using the class
<b>Exception
</b>.
</p>
180 <p class=
"p2"><br></p>
181 <p class=
"p7">try {
1+
1 }
</p>
183 <p class=
"p2"><br></p>
184 <p class=
"p5">// can't add a Point to an integer - binary op failed error
</p>
185 <p class=
"p5">// result of catch func is returned instead
</p>
186 <p class=
"p7">try {
1+
<span class=
"s2">Point
</span>(
0,
0) } {
2*
5 }
</p>
188 <p class=
"p2"><br></p>
189 <p class=
"p4"><b>3. Common primitive errors
<span class=
"Apple-converted-space"> </span></b></p>
190 <p class=
"p2"><br></p>
191 <p class=
"p3"><b>- operation cannot be called from this Process.
<span class=
"Apple-converted-space"> </span></b></p>
192 <p class=
"p2"><br></p>
193 <p class=
"p3">This is usually the results of performing a GUI operation within a routine or scheduled function that is executing on some clock other than AppClock. AppClock is the only clock that can execute GUI manipulation because it is a lower priority thread. If the CPU is busy with audio synthesis or maintaining accurate scheduling for musical events, AppClock events will be delayed until the CPU is free enough.
<span class=
"Apple-converted-space"> </span></p>
194 <p class=
"p2"><br></p>
195 <p class=
"p3">Solution: write your GUI updates as follows.
<b>defer
</b> schedules the function on AppClock.
</p>
196 <p class=
"p2"><br></p>
197 <p class=
"p7">{ myGUIObject.value_(newValue) }.defer;
<span class=
"Apple-converted-space"> </span></p>
198 <p class=
"p2"><br></p>
199 <p class=
"p3"><b>- Attempted write to immutable object.
<span class=
"Apple-converted-space"> </span></b></p>
200 <p class=
"p2"><br></p>
201 <p class=
"p7">#[
0,
1,
2].put(
1,
3)
</p>
202 <p class=
"p9"><br></p>
203 <p class=
"p7">ERROR: Primitive '_BasicPut' failed.
</p>
204 <p class=
"p7">Attempted write to immutable object.
</p>
205 <p class=
"p2"><br></p>
206 <p class=
"p3">#[
0,
1,
2] is a literal array. Literal arrays cannot be manipulated--they can only be indexed. They cannot be changed internally.
<span class=
"Apple-converted-space"> </span></p>
207 <p class=
"p2"><br></p>
208 <p class=
"p3">Solution: copy the array first.
</p>
209 <p class=
"p2"><br></p>
210 <p class=
"p7">#[
0,
1,
2].copy.put(
1,
3)
</p>
211 <p class=
"p9"><br></p>
212 <p class=
"p7">[
0,
3,
2 ]
<span class=
"Apple-converted-space"> </span></p>
213 <p class=
"p2"><br></p>
214 <p class=
"p3"><b>- Index not an Integer.
</b></p>
215 <p class=
"p2"><br></p>
216 <p class=
"p7">#[
0,
1,
2].at(\
1)
</p>
217 <p class=
"p9"><br></p>
218 <p class=
"p7">ERROR: Primitive '_BasicAt' failed.
</p>
219 <p class=
"p7">Index not an Integer
</p>
220 <p class=
"p2"><br></p>
221 <p class=
"p3">Arrays can be indexed only with integers (or, in builds since August
2004, floats).
</p>
222 <p class=
"p2"><br></p>
223 <p class=
"p3">Solution: use .asInteger—note that if the object cannot be converted into an integer, you'll get a
"Does not understand" error!
</p>
224 <p class=
"p2"><br></p>
225 <p class=
"p7">#[
0,
1,
2].at(\
1.asInteger)
</p>
227 <p class=
"p2"><br></p>
228 <p class=
"p3"><b>- Index out of range.
</b></p>
229 <p class=
"p2"><br></p>
230 <p class=
"p7">[
0,
1,
2].put(
5,
5)
</p>
231 <p class=
"p9"><br></p>
232 <p class=
"p7">ERROR: Primitive '_BasicPut' failed.
</p>
233 <p class=
"p7">Index out of range.
</p>
234 <p class=
"p2"><br></p>
235 <p class=
"p3">Arrays have a finite size. If you try to put an object into an array slot but the slot does not exist because the array is too small, you'll get this error.
<span class=
"Apple-converted-space"> </span></p>
236 <p class=
"p2"><br></p>
237 <p class=
"p3">Solution: extend the array.
</p>
238 <p class=
"p2"><br></p>
239 <p class=
"p7">[
0,
1,
2].extend(
6).put(
5,
5)
</p>
240 <p class=
"p9"><br></p>
241 <p class=
"p7">[
0,
1,
2, nil, nil,
5 ]
</p>
242 <p class=
"p9"><br></p>
243 <p class=
"p3">Note that if the argument to extend() is smaller than the array, then the array will be truncated. If you're not sure, use max:
</p>
244 <p class=
"p9"><br></p>
245 <p class=
"p7">i = rrand(
5,
10);
</p>
246 <p class=
"p7">a = [
0,
1,
2];
</p>
247 <p class=
"p7">a.extend(max(i+
1, a.size)).put(i,
100);
</p>
248 <p class=
"p2"><br></p>
249 <p class=
"p3">Why i+
1? An array with size
4 allows
0,
1,
2 and
3 as indexes (
4 elements starting with
0).
</p>
250 <p class=
"p2"><br></p>
251 <p class=
"p3">If it's a new array, use .newClear instead of .new.
</p>
252 <p class=
"p2"><br></p>
253 <p class=
"p7">a =
<span class=
"s2">Array
</span>.new(
4);
</p>
254 <p class=
"p7">a.put(
3,
1);
</p>
255 <p class=
"p7">ERROR: Primitive '_BasicPut' failed.
</p>
256 <p class=
"p7">Index out of range.
</p>
257 <p class=
"p9"><br></p>
258 <p class=
"p7">a =
<span class=
"s2">Array
</span>.newClear(
4);
</p>
259 <p class=
"p7">a.put(
3,
1);
</p>
260 <p class=
"p7">[ nil, nil, nil,
1 ]
</p>
261 <p class=
"p9"><br></p>
262 <p class=
"p9"><br></p>
263 <p class=
"p9"><br></p>
264 <p class=
"p4"><b>4. A common network error
</b></p>
265 <p class=
"p9"><br></p>
266 <p class=
"p9"><br></p>
267 <p class=
"p7">Exception in World_OpenUDP: unable to bind udp socket
</p>
268 <p class=
"p2"><br></p>
269 <p class=
"p3">This is because you have multiple servers running, left over from crashes, unexpected quits etc.
</p>
270 <p class=
"p3">One can't cause them to quit via OSC (the boot button).
</p>
271 <p class=
"p9"><br></p>
272 <p class=
"p5">// use this to remove them:
</p>
273 <p class=
"p7"><span class=
"s2">Server
</span>.killAll
<span class=
"Apple-converted-space"> </span></p>
274 <p class=
"p2"><br></p>
275 <p class=
"p2"><br></p>
276 <p class=
"p2"><br></p>
277 <p class=
"p4"><b>5. A common warning
</b></p>
278 <p class=
"p2"><br></p>
279 <p class=
"p7">WARNING: FunctionDef contains variable declarations and so will not be inlined.
</p>
280 <p class=
"p2"><br></p>
281 <p class=
"p3">This warning can be safely ignored. Your code will still run, even if you get this warning.
<span class=
"Apple-converted-space"> </span></p>
282 <p class=
"p2"><br></p>
283 <p class=
"p3">Inlining is a compiler optimization that takes the operations inside a function and places them in the main line of the containing function. For instance,
<span class=
"Apple-converted-space"> </span></p>
284 <p class=
"p2"><br></p>
285 <p class=
"p5">// inlined
</p>
286 <p class=
"p7">{ while {
0.9.coin } {
10.rand.postln }
</p>
287 <p class=
"p7">}.def.dumpByteCodes;
</p>
288 <p class=
"p2"><br></p>
289 <p class=
"p7">BYTECODES: (
16)
</p>
290 <p class=
"p7"><span class=
"Apple-converted-space"> </span>0 <span class=
"Apple-converted-space"> </span>40 <span class=
"Apple-converted-space"> </span>PushLiteral Float
0.9 <span class=
"Apple-converted-space"> </span>3FECCCCC CCCCCCCD
<span class=
"Apple-converted-space"> </span><span class=
"s3">// {
0.9.coin }
</span></p>
291 <p class=
"p7"><span class=
"Apple-converted-space"> </span>1 <span class=
"Apple-converted-space"> </span>0D
2C
<span class=
"Apple-converted-space"> </span>SendSpecialUnaryArithMsgX 'coin'
</p>
292 <p class=
"p7"><span class=
"Apple-converted-space"> </span>3 <span class=
"Apple-converted-space"> </span>F9
00 09 JumpIfFalsePushNil
9<span class=
"Apple-converted-space"> </span>(
15)
</p>
293 <p class=
"p7"><span class=
"Apple-converted-space"> </span>6 <span class=
"Apple-converted-space"> </span>2C
0A
<span class=
"Apple-converted-space"> </span>PushInt
10<span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-converted-space"> </span><span class=
"s3">// {
10.rand.postln }
</span></p>
294 <p class=
"p7"><span class=
"Apple-converted-space"> </span>8 <span class=
"Apple-converted-space"> </span>0D
25<span class=
"Apple-converted-space"> </span>SendSpecialUnaryArithMsgX 'rand'
</p>
295 <p class=
"p7"><span class=
"Apple-converted-space"> </span>10 <span class=
"Apple-converted-space"> </span>C1
38<span class=
"Apple-converted-space"> </span>SendSpecialMsg 'postln'
</p>
296 <p class=
"p7"><span class=
"Apple-converted-space"> </span>12 <span class=
"Apple-converted-space"> </span>FD
00 0D JumpBak
13<span class=
"Apple-converted-space"> </span>(
0)
</p>
297 <p class=
"p7"><span class=
"Apple-converted-space"> </span>15 <span class=
"Apple-converted-space"> </span>F2
<span class=
"Apple-converted-space"> </span>BlockReturn
</p>
298 <p class=
"p7">a FunctionDef in closed FunctionDef
</p>
299 <p class=
"p2"><br></p>
300 <p class=
"p3">This function contains two other functions. One is the condition for the while loop; the other is the while loop's action. The compiler renders this into a single code block, using jump instructions to handle the looping and exit.
<span class=
"Apple-converted-space"> </span></p>
301 <p class=
"p2"><br></p>
302 <p class=
"p3">If, however, one of the functions defines a variable, then that function requires a separate execution frame. In this case, it's necessary for the compiler to push function definition objects onto the stack.
<span class=
"Apple-converted-space"> </span></p>
303 <p class=
"p2"><br></p>
304 <p class=
"p5">// not inlined
</p>
305 <p class=
"p7">{ while {
0.9.coin } {
</p>
306 <p class=
"p5"><span class=
"s1"><span class=
"Apple-converted-space"> </span></span><span class=
"s2">var
</span><span class=
"s1"> a;
<span class=
"Apple-tab-span"> </span></span>// variable here prevents optimization
</p>
307 <p class=
"p7"><span class=
"Apple-converted-space"> </span>a =
10.rand;
</p>
308 <p class=
"p7"><span class=
"Apple-converted-space"> </span>a.postln
</p>
309 <p class=
"p7"><span class=
"Apple-converted-space"> </span>}
</p>
310 <p class=
"p7">}.def.dumpByteCodes;
</p>
311 <p class=
"p2"><br></p>
312 <p class=
"p7">BYTECODES: (
7)
</p>
313 <p class=
"p7"><span class=
"Apple-converted-space"> </span>0 <span class=
"Apple-converted-space"> </span>04 00<span class=
"Apple-converted-space"> </span>PushLiteralX instance of FunctionDef in closed FunctionDef
</p>
314 <p class=
"p7"><span class=
"Apple-converted-space"> </span>2 <span class=
"Apple-converted-space"> </span>04 01<span class=
"Apple-converted-space"> </span>PushLiteralX instance of FunctionDef in closed FunctionDef
</p>
315 <p class=
"p7"><span class=
"Apple-converted-space"> </span>4 <span class=
"Apple-converted-space"> </span>C2
0C
<span class=
"Apple-converted-space"> </span>SendSpecialMsg 'while'
</p>
316 <p class=
"p7"><span class=
"Apple-converted-space"> </span>6 <span class=
"Apple-converted-space"> </span>F2
<span class=
"Apple-converted-space"> </span>BlockReturn
</p>
317 <p class=
"p7">a FunctionDef in closed FunctionDef
</p>
318 <p class=
"p2"><br></p>
319 <p class=
"p3">Inlined code will run faster, because pushing and using different execution frames is extra work for the virtual machine. If you're very concerned about speed, you can use this warning as an indicator that you might be able to optimize something in your code further.
<span class=
"Apple-converted-space"> </span></p>
320 <p class=
"p2"><br></p>
321 <p class=
"p3">Sometimes, there's no way around un-optimized code. To wit,
<span class=
"Apple-converted-space"> </span></p>
322 <p class=
"p2"><br></p>
323 <p class=
"p5">// inlined, optimized, but you'll get stuck notes
</p>
324 <p class=
"p8">Routine
<span class=
"s1">({
</span></p>
325 <p class=
"p7"><span class=
"Apple-converted-space"> </span><span class=
"s2">var
</span> synth;
</p>
326 <p class=
"p7"><span class=
"Apple-converted-space"> </span>{ synth =
<span class=
"s2">Synth
</span>(
<span class=
"s4">"someSynth"</span>, [...args...]);
</p>
327 <p class=
"p7"><span class=
"Apple-converted-space"> </span><span class=
"s2">thisThread
</span>.clock.sched(
10, {
</p>
328 <p class=
"p7"><span class=
"Apple-converted-space"> </span>synth.free;
</p>
329 <p class=
"p7"><span class=
"Apple-converted-space"> </span>});
</p>
330 <p class=
"p7"><span class=
"Apple-converted-space"> </span>2.wait;
</p>
331 <p class=
"p7"><span class=
"Apple-converted-space"> </span>}.loop;
</p>
332 <p class=
"p7">}).play;
</p>
333 <p class=
"p9"><br></p>
334 <p class=
"p5">// not inlined, but no stuck notes
</p>
335 <p class=
"p8">Routine
<span class=
"s1">({
</span></p>
336 <p class=
"p7"><span class=
"Apple-converted-space"> </span>{
<span class=
"s2">var
</span> synth;
</p>
337 <p class=
"p7"><span class=
"Apple-converted-space"> </span>synth =
<span class=
"s2">Synth
</span>(
<span class=
"s4">"someSynth"</span>, [...args...]);
</p>
338 <p class=
"p7"><span class=
"Apple-converted-space"> </span><span class=
"s2">thisThread
</span>.clock.sched(
10, {
</p>
339 <p class=
"p7"><span class=
"Apple-converted-space"> </span>synth.free;
</p>
340 <p class=
"p7"><span class=
"Apple-converted-space"> </span>});
</p>
341 <p class=
"p7"><span class=
"Apple-converted-space"> </span>2.wait;
</p>
342 <p class=
"p7"><span class=
"Apple-converted-space"> </span>}.loop;
</p>
343 <p class=
"p7">}).play;
</p>
344 <p class=
"p2"><br></p>
345 <p class=
"p3">The first routine can be optimized because there is no variable declaration inside the loop. But, the synth variable changes on each iteration, meaning that by the time the first release happens, you don't have access anymore to the first note. Thus the first note will never terminate.
<span class=
"Apple-converted-space"> </span></p>
346 <p class=
"p2"><br></p>
347 <p class=
"p3">In the second case, each note has its own synth variable, so the notes will be terminated as expected. You get a warning, but it's better because the results are correct.
</p>
348 <p class=
"p2"><br></p>
349 <p class=
"p2"><br></p>
350 <p class=
"p3">A solution to the above problem is to use a function with local variables.
<span class=
"Apple-converted-space"> </span></p>
351 <p class=
"p2"><br></p>
353 <p class=
"p8">Routine
<span class=
"s1">({
</span></p>
354 <p class=
"p7"><span class=
"Apple-tab-span"> </span><span class=
"s2">var
</span> func;
</p>
355 <p class=
"p7"><span class=
"Apple-tab-span"> </span>func = {
<span class=
"Apple-converted-space"> </span></p>
356 <p class=
"p5"><span class=
"s1"><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span><span class=
"s2">var
</span><span class=
"s1"> synth;
</span>// this variable is local to the function
</p>
357 <p class=
"p7"><span class=
"Apple-converted-space"> <span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>synth =
<span class=
"s2">Synth
</span>(
<span class=
"s4">"default"</span>);
</p>
358 <p class=
"p7"><span class=
"Apple-converted-space"> <span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>[
<span class=
"s5">\play
</span>, synth].postln;
</p>
359 <p class=
"p7"><span class=
"Apple-converted-space"> <span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span><span class=
"s2">thisThread
</span>.clock.sched(
4.5, {
<span class=
"Apple-converted-space"> </span></p>
360 <p class=
"p7"><span class=
"Apple-converted-space"> <span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>synth.free;
</p>
361 <p class=
"p7"><span class=
"Apple-converted-space"> <span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>[
<span class=
"s5">\free
</span>, synth].postln;
<span class=
"Apple-converted-space"> </span></p>
362 <p class=
"p7"><span class=
"Apple-converted-space"> <span class=
"Apple-tab-span"> </span><span class=
"Apple-tab-span"> </span></span>});
</p>
363 <p class=
"p7"><span class=
"Apple-converted-space"> <span class=
"Apple-tab-span"> </span></span>};
</p>
364 <p class=
"p7"><span class=
"Apple-converted-space"> <span class=
"Apple-tab-span"> </span></span>{ func.value;
1.wait; }.loop
</p>
365 <p class=
"p7">}).play;
</p>
367 <p class=
"p2"><br></p>