title:: 22_Runtime_errors
summary:: Mark Polishook tutorial
categories:: Tutorials>Mark_Polishook_tutorial
related:: Tutorials/Mark_Polishook_tutorial/00_Introductory_tutorial

section::Runtime errors

Runtime errors occur while a program is executing.

section::Common errors

numberedList::
## an object receives a message which it doesn't understand
## a binary operation (addition, subtraction, multiplication, etc.) can't be performed
## a value other than true or false appears in a conditional (boolean) test
## a file can't be opened (a primitive fails)
::

section::Object doesn't understand

In the case of

code::
3.createRuntimeError
::

SuperCollider prints a four-part error notification to the post window. The parts of the notification are ERROR, RECEIVER, ARGS, and CALL STACK, as in

code::
ERROR: Message 'createRuntimeError' not understood.
RECEIVER:
   Integer 3
ARGS:
Instance of Array {    (057E7560, gc=01, fmt=01, flg=11, set=00)
  indexed slots [0]
}
CALL STACK:
	DoesNotUnderstandError-reportError
		arg this = <instance of DoesNotUnderstandError>
	Nil-handleError
		arg this = nil
		arg error = <instance of DoesNotUnderstandError>
	Object-throw
		arg this = <instance of DoesNotUnderstandError>
	Object-doesNotUnderstand
		arg this = 3
		arg selector = 'createRuntimeError'
		arg args = [*0]
	< closed FunctionDef >  (no arguments or variables)
	Interpreter-interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
	Process-interpretPrintCmdLine
		arg this = <instance of Main>
::

////////////////////////////////////////////////////////////////////////////////////////////////////

The ERROR section explains what went wrong. The RECEIVER section names the class of the object to which the message was sent. The ARGS section says how many arguments were included in the message. Read the CALL STACK from the bottom to the top to see where the error happened. Reading from bottom to top means going from

code::
Process-interpretPrintCmdLine
::

to

code::
Interpreter-interpretPrintCmdLine
::

to

code::
Object-doesNotUnderstand
::

to

code::
Object-throw
::

to

code::
Nil-handleError
::

to

code::
DoesNotUnderstandError-reportError
::

which is the first line in the stack.

////////////////////////////////////////////////////////////////////////////////////////////////////

code::
DoesNotUnderstandError-reportError
::

is the mechanism that prints the error notification to the post window. Select it and press cmd-j to see how it works (how it prints the notification).

////////////////////////////////////////////////////////////////////////////////////////////////////

Execute

code::
$a * $b
::

to create another runtime error message.

////////////////////////////////////////////////////////////////////////////////////////////////////

The ERROR, RECEIVER, ARGS, and CALL STACK headers in the post window explain the problem: Instances of class Char have no knowledge of multiplication.

code::
ERROR: Message '*' not understood.
RECEIVER:
   Character 97 'a'
ARGS:
Instance of Array {    (067F5470, gc=C4, fmt=01, flg=00, set=01)
  indexed slots [1]
      0 : Character 98 'b'
}
CALL STACK:
	DoesNotUnderstandError-reportError
		arg this = <instance of DoesNotUnderstandError>
	Nil-handleError
		arg this = nil
		arg error = <instance of DoesNotUnderstandError>
	Object-throw
		arg this = <instance of DoesNotUnderstandError>
	Object-doesNotUnderstand
		arg this = $a
		arg selector = '*'
		arg args = [*1]
	< closed FunctionDef >  (no arguments or variables)
	Interpreter-interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
	Process-interpretPrintCmdLine
		arg this = <instance of Main>
::

section::Uninitialized variable (binary operation fails)

Here, the variable a is initialized to an integer and the variable b isn't initialized. Multiplying a (the integer 10) by b (nil, the value that SuperCollider uses for uninitialized data) will create a runtime error.

code::
(
var a = 10;	// a is declared and initialized
var b;		// b declared but not initialized, so it defaults to nil

t = Task({

	4.do({ arg item, i;

		if(i != 3)
			{ i.postln } 		// print the value of i if it doesn't equal 3
			{ (a * b).postln };	// when i equals 3, do a * b
						// ... which is a problem if b is nil
		1.wait;

	})

});
t.start;
)
::

////////////////////////////////////////////////////////////////////////////////////////////////////

The printout shows the code ran successfully until the index, i, reached 3, which is when a * b happened. The ERROR, RECEIVER, ARGS, and CALL STACK headers describe the problem.

////////////////////////////////////////////////////////////////////////////////////////////////////

code::
a Task
0
1
2
ERROR: binary operator '*' failed.
RECEIVER:
   nil
ARGS:
Instance of Array {    (067D92B0, gc=CC, fmt=01, flg=00, set=01)
  indexed slots [2]
      0 : Integer 10
      1 : nil
}
CALL STACK:
	DoesNotUnderstandError-reportError
		arg this = <instance of BinaryOpFailureError>
	Nil-handleError
		arg this = nil
		arg error = <instance of BinaryOpFailureError>
	Object-throw
		arg this = <instance of BinaryOpFailureError>
	Object-performBinaryOpOnSomething
		arg this = nil
		arg aSelector = '*'
		arg thing = 10
		arg adverb = nil
	Integer-*
		arg this = 10
		arg aNumber = nil
		arg adverb = nil
	< FunctionDef in closed FunctionDef >
		arg item = 3
		arg i = 3
	Integer-do
		arg this = 4
		arg function = <instance of Function>
		var i = 3
	< FunctionDef in closed FunctionDef >  (no arguments or variables)
	Routine-prStart
		arg this = <instance of Routine>
		arg inval = 758.000000
::

////////////////////////////////////////////////////////////////////////////////////////////////////

section::True, false, or other

A value other than true or false in a boolean test, as in

code::
if(x=4) { "this is ok"};
::

produces

code::
ERROR: Non Boolean in test.
RECEIVER:
   Integer 4
CALL STACK:
	MethodError-reportError
		arg this = <instance of MustBeBooleanError>
	Nil-handleError
		arg this = nil
		arg error = <instance of MustBeBooleanError>
	Object-throw
		arg this = <instance of MustBeBooleanError>
	Object-mustBeBoolean
		arg this = 4
	< closed FunctionDef >  (no arguments or variables)
	Interpreter-interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
	Process-interpretPrintCmdLine
		arg this = <instance of Main>
::

////////////////////////////////////////////////////////////////////////////////////////////////////

Correcting the test clause fixes the problem.

code::
if(x==4) { "this is ok"};
::

////////////////////////////////////////////////////////////////////////////////////////////////////

section::Primitive fails

Asking for the length of a non-existent file creates a runtime error. The notification shows what went wrong (a C code primitive failed).

code::
f = File("i_don't_exist", "r");
f.length;

ERROR: Primitive '_FileLength' failed.
Failed.
RECEIVER:
Instance of File {    (067D9970, gc=C4, fmt=00, flg=00, set=01)
  instance variables [1]
    fileptr : nil
}
CALL STACK:
	MethodError-reportError
		arg this = <instance of PrimitiveFailedError>
	Nil-handleError
		arg this = nil
		arg error = <instance of PrimitiveFailedError>
	Object-throw
		arg this = <instance of PrimitiveFailedError>
	Object-primitiveFailed
		arg this = <instance of File>
	File-length
		arg this = <instance of File>
	< closed FunctionDef >  (no arguments or variables)
	Interpreter-interpretPrintCmdLine
		arg this = <instance of Interpreter>
		var res = nil
		var func = <instance of Function>
	Process-interpretPrintCmdLine
		arg this = <instance of Main>
::

////////////////////////////////////////////////////////////////////////////////////////////////////
