Handling Errors

Errors are anomalous or exceptional conditions which require special processing. So, exception handling is the process of responding to exceptional circumstances which occur during computation.

Why Use Exception Handling?

What other alternatives do we have if we do not use exception handling? We can use the if-else statement for error detection, reporting and handling. For example, suppose we have a method which reads an entire file into memory. This method does the following tasks in order:

  • Open the file
  • Determine the size
  • Allocate that much into memory
  • Read the file into memory
  • Close the file
  • However, we might encounter some problems in each tasks such as the file cannot be opened, not enough memory can be allocated, the file cannot be read and many more. Without handling these problems, the program will then crash. Hence, we program the code such that it does error detection and handles all these errors. One way in doing this is as follows:

    Suppose we have the following words:

    	: try-open-file
    		file? not      -> -1 |
    		size? not      -> -2 |
    		allocate? not  -> -3 |
    		...
    		...
    		otherwise         0 |.
    	;
    	

    As you can see, there are much testing to be done, and it would be likely to miss some of the checks, causing the program to crash. For cases with even more errors that need to be detected, we might get lost in it. It would also be hard to find bugs in the code.

    There is another disadvantage if we do not have exception handling. Suppose that the method above is within a series of nested methods. In other words, consider a case where we run a method called function1, which calls another method named function2, which calls the above method to read a file. We will then need to pass the error from the reading file method into function2 and then function1. All the functions involved will need to check for errors, even for those functions that are not interested in detecting errors. For a program with long nested methods, there would be a huge error bubbles.

    Using exception handling will help solve these two main problems, which helps simplify our code. 
    	   Instead of having to write all the if-else statement and bubble errors up the series of functions, we can just use the 
    THROW
    and
    CATCH
    mechanism. If the program catches an exception, it will just abort the task which throws the exception and return to the state before the current task has been conducted. In Smojo, we can see that in the case of an error, the depth of the stack remains the same.

    Smojo provides a number of words for exception handling. The Stack Changes are conditions of the stack before and after while z*x means z items are on the stack.

    Word Action
    THROW

    Takes one argument, the error number. This word halts the further execution of a word, and puts execution at the point
    CATCH
    was last called.

    Stack Changes: ( n = error number ) k*x n -- k*x n
    CATCH

    Takes an XT and runs it. If somewhere in it, the system
    THROW
    s an exception, the XTs execution is halted and the
    THROW
    's error number is placed on the stack. In the case of an error, the depth of the stack is left unchanged.

    Stack Changes: ( 0 = no error , n = error number ) i*x xt -- j*x 0 | i*x n
    TRY

    Executes the given XT and signals an error if thrown (
    TRUE
    if there is an error and
    FALSE
    otherwise). Two kinds of errors are caught:
  • Java errors are signalled using the error number -3. Also the java error object itself is put on the stack.
  • Smojo exceptions using the
    THROW
    mechanism is signalled using the error number -2.

  • Stack Change: ( n = -3 for java error, n = -2 for
    THROW
    generated exception) i*x xt -- j*x false | k*x error n true | l*x n true
    ABORT

    Unconditionally sets the runtime's exception flag and creates a multi-level exit.

    Examples

    Example 1
    	: negative? dup 0 < if 100 throw else 1 + then ;
    	
    	10 ' negative? catch .s
    	<2> 11 0 
    	ok
    	
    	-10 ' negative? catch .s
    	<2> -10 100 
    	ok
    	
    Example 2
    	: problem
    	     "problem" .
    	     1 throw
    	     "but you'll never see it again." . ;
    
    	: rocket "houston we have a" . problem "time to abort" . ;
    
    	: launch
    	     ['] rocket catch
    	     0 =    -> cr "Success!" . 	|
    	     otherwise cr "Fail!" . 	|.
    	;
    
    	launch
    	houston we have a problem
    	Fail! ok	
    
    	
    Example 3
    	1 :> 1 + + ; try .s
    	<3> java.lang.ArrayIndexOutOfBoundsException -3 true 
    	ok
    	

    Quiz

    Question 1

    Explain the logical flow of the program in Example 2.



    Question 2

    Write a word 
    /0?
    that takes two numbers as arguments. It throws an error if the second number is zero. Otherwise, divide the two numbers as usual.



    Next: Parsing & the Token Stream