supernova: fix for small audio vector sizes
[supercollider.git] / HelpSource / Guides / Understanding-Errors.schelp
blob37625de0ab457880815754b1c4fec52681238d7e
1 title:: Understanding errors
2 summary:: a guide to understanding errors
3 related:: Guides/Debugging-tips
4 categories:: Language, Debugging
6 section:: Reading error dumps
8 When sc3 reports an error to the user, there are usually three parts:
9 list::
10 ## the error text
11 ## a dump of the receiver of the method that caused the error, and/or any arguments of the method call
12 ## a dump of the call stack to the point of the error
15 For example:
16 code::
17 1.blech  // no class implements this method; therefore you'll get an error
19 // error text
20 ERROR: Message 'blech' not understood.
22 // receiver and args
23 RECEIVER:
24    Integer 1
25 ARGS:
26 Instance of Array {    (02207560, gc=01, fmt=01, flg=11, set=00)
27   indexed slots [0]
30 // call stack
31 CALL STACK:
32         DoesNotUnderstandError-reportError
33                 arg this = <instance of DoesNotUnderstandError>
34         Nil-handleError
35                 arg this = nil
36                 arg error = <instance of DoesNotUnderstandError>
37         Object-throw
38                 arg this = <instance of DoesNotUnderstandError>
39         Object-doesNotUnderstand
40                 arg this = 1
41                 arg selector = 'blech'
42                 arg args = [*0]
43         < closed FunctionDef >  (no arguments or variables)
44         Interpreter-interpretPrintCmdLine
45                 arg this = <instance of Interpreter>
46                 var res = nil
47                 var func = <instance of Function>
48         Process-interpretPrintCmdLine
49                 arg this = <instance of Main>
51 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.
53 definitionlist::
54 ## Error text || 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.
55 ## Receiver and arguments || The method was applied to an integer (1), with no arguments (the size of the arguments array is 0).
56 ## Call stack || Order of execution in the call stack is in reverse: the top of the stack shows the most recent calls.
59 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).
60 You can ignore these three calls.
62 Following is the meat: the error happened when an object was not understood. Continuing to read down, it happened inside a function definition.
63 (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.)
64 And, it all began with the instruction to interpret and print a command line.
66 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.
67 code::
68 Routine({
69         var a;
70         a = 5;
71         loop {
72                 var b;
73                 b = 20.rand;
74                 b.postln.ecky_ecky_phtang;   // "NI!!!!"
75                 a.wait;
76         }
77 }).play;
79 ERROR: Message 'ecky_ecky_phtang' not understood.
80 RECEIVER:
81    Integer 6
82 ARGS:
83 Instance of Array {    (02207560, gc=01, fmt=01, flg=11, set=00)
84   indexed slots [0]
86 CALL STACK:
87         DoesNotUnderstandError-reportError
88                 arg this = <instance of DoesNotUnderstandError>
89         Nil-handleError
90                 arg this = nil
91                 arg error = <instance of DoesNotUnderstandError>
92         Object-throw
93                 arg this = <instance of DoesNotUnderstandError>
94         Object-doesNotUnderstand
95                 arg this = 6
96                 arg selector = 'ecky_ecky_phtang'
97                 arg args = [*0]
98         < FunctionDef in closed FunctionDef >
99                 var b = 6
100         Function-loop
101                 arg this = <instance of Function>
102         < FunctionDef in closed FunctionDef >
103                 var a = 5
104         Routine-prStart
105                 arg this = <instance of Routine>
106                 arg inval = 1542.075067
108 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).
109 Note that there are two calls identified as "FunctionDef in closed FunctionDef" and that they can be distinguished by the variables contained within.
110 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 called within another function defining "a" inside a routine.
112 What if the error occurred not inside a function definition that you wrote, but inside a method in the class library?
113 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.
115 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.
117 section:: Error objects and error handling
119 sc3 implements error reporting using Error objects, which are instances of the class Error or one of its subclasses.
120 Any code (whether in the class library or any user application) can throw an error any time as follows:
121 code::
122 Error("This is a basic error.").throw;
124 You can also catch exceptions that occur within functions by executing the function with code::try:: or code::protect:: instead of code::value::.
126 definitionlist::
127 ## try || 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.
128 In this example, we do not rethrow the error, so the error is swallowed and execution continues to the end.
129 code::
130 try { 1.blech } { |error| "oops".postln };
131 "next line".postln;
133 oops
134 next line
136 ## protect || executes the first function. On an error, execute the second function before reporting the error.
137 This is useful when the steps before the protect make some changes that need to be undone if an error occurs.
138 See link::Classes/Environment#use#Environment:use:: for an example.
139 code::
140 protect { 1.blech } { |error| "oops".postln };
141 "next line".postln;
143 oops  // without protect, this would not be posted
144 ERROR: Message 'blech' not understood.
145 RECEIVER:
146    Integer 1
147 ARGS:
148 Instance of Array {    (02207560, gc=01, fmt=01, flg=11, set=00)
149   indexed slots [0]
151 CALL STACK:
152         DoesNotUnderstandError-reportError
153                 arg this = <instance of DoesNotUnderstandError>
157 Prior to August 2004, try and protect do not return the value of the function to the caller if there is no error.
158 code::
159 try { 1+1 }
161 a Function
163 More recent builds (since early August 2004) do return the function's value. Non-error objects can be thrown using the class Exception.
164 code::
165 try { 1+1 }
168 // can't add a Point to an integer - binary op failed error
169 // result of catch func is returned instead
170 try { 1+Point(0, 0) } { 2*5 }
174 section:: Common primitive errors
176 subsection:: operation cannot be called from this Process.
178 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.
179 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.
181 Solution: write your GUI updates as follows. defer schedules the function on AppClock.
182 code::
183 { myGUIObject.value_(newValue) }.defer;
186 subsection:: Attempted write to immutable object.
187 code::
188 #[0, 1, 2].put(1, 3)
190 ERROR: Primitive '_BasicPut' failed.
191 Attempted write to immutable object.
193 code:: #[0, 1, 2] :: is a literal array. Literal arrays cannot be manipulated--they can only be indexed. They cannot be changed internally.
195 Solution: copy the array first.
196 code::
197 #[0, 1, 2].copy.put(1, 3)
199 [ 0, 3, 2 ]
202 subsection:: Index not an Integer.
203 code::
204 #[0, 1, 2].at(\1)
206 ERROR: Primitive '_BasicAt' failed.
207 Index not an Integer
209 Arrays can be indexed only with integers (or, in builds since August 2004, floats).
211 Solution: use code:: .asInteger ::
212 code::
213 #[0, 1, 2].at(\1.asInteger)
216 note:: if the object cannot be converted into an integer, you'll get a "Does not understand" error! ::
218 subsection:: Index out of range.
219 code::
220 [0, 1, 2].put(5, 5)
222 ERROR: Primitive '_BasicPut' failed.
223 Index out of range.
225 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.
227 Solution: extend the array.
228 code::
229 [0, 1, 2].extend(6).put(5, 5)
231 [ 0, 1, 2, nil, nil, 5 ]
233 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:
234 code::
235 i = rrand(5, 10);
236 a = [0, 1, 2];
237 a.extend(max(i+1, a.size)).put(i, 100);
239 Why i+1? An array with size 4 allows 0, 1, 2 and 3 as indexes (4 elements starting with 0).
241 If it's a new array, use .newClear instead of .new.
242 code::
243 a = Array.new(4);
244 a.put(3, 1);
245 ERROR: Primitive '_BasicPut' failed.
246 Index out of range.
248 a = Array.newClear(4);
249 a.put(3, 1);
250 [ nil, nil, nil, 1 ]
253 section:: A common network error
255 code::
256 Exception in World_OpenUDP: unable to bind udp socket
258 This is because you have multiple servers running, left over from crashes, unexpected quits etc.
259 One can't cause them to quit via OSC (the boot button).
261 use this to remove them:
262 code::
263 Server.killAll
266 section:: A common warning
267 code::
268 WARNING: FunctionDef contains variable declarations and so will not be inlined.
270 This warning can be safely ignored. Your code will still run, even if you get this warning.
272 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,
273 code::
274 // inlined
275 { while { 0.9.coin } { 10.rand.postln }
276 }.def.dumpByteCodes;
278 BYTECODES: (16)
279   0   40       PushLiteral Float 0.9   3FECCCCC CCCCCCCD  // { 0.9.coin }
280   1   0D 2C    SendSpecialUnaryArithMsgX 'coin'
281   3   F9 00 09 JumpIfFalsePushNil 9  (15)
282   6   2C 0A    PushInt 10                                                         // { 10.rand.postln }
283   8   0D 25    SendSpecialUnaryArithMsgX 'rand'
284  10   C1 38    SendSpecialMsg 'postln'
285  12   FD 00 0D JumpBak 13  (0)
286  15   F2       BlockReturn
287 a FunctionDef in closed FunctionDef
289 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.
291 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.
292 code::
293 // not inlined
294 { while { 0.9.coin } {
295     var a;      // variable here prevents optimization
296     a = 10.rand;
297     a.postln
298   }
299 }.def.dumpByteCodes;
301 BYTECODES: (7)
302   0   04 00    PushLiteralX instance of FunctionDef in closed FunctionDef
303   2   04 01    PushLiteralX instance of FunctionDef in closed FunctionDef
304   4   C2 0C    SendSpecialMsg 'while'
305   6   F2       BlockReturn
306 a FunctionDef in closed FunctionDef
308 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.
310 Sometimes, there's no way around un-optimized code. To wit,
311 code::
312 // inlined, optimized, but you'll get stuck notes
313 Routine({
314   var synth;
315   { synth = Synth("someSynth", [...args...]);
316     thisThread.clock.sched(10, {
317       synth.free;
318     });
319     2.wait;
320   }.loop;
321 }).play;
323 // not inlined, but no stuck notes
324 Routine({
325   { var synth;
326     synth = Synth("someSynth", [...args...]);
327     thisThread.clock.sched(10, {
328       synth.free;
329     });
330     2.wait;
331   }.loop;
332 }).play;
334 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.
335 Thus the first note will never terminate.
337 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.
339 A solution to the above problem is to use a function with local variables.
340 code::
342 Routine({
343     var func;
344     func = {
345         var synth; // this variable is local to the function
346         synth = Synth("default");
347         [\play, synth].postln;
348         thisThread.clock.sched(4.5, {
349             synth.free;
350                 [\free, synth].postln;
351         });
352     };
353     { func.value; 1.wait; }.loop
354 }).play;