Exception handling Programming Language Design and Implementation (4th Edition) by T. Pratt and M. Zelkowitz Prentice Hall, 2001 Section 11.1
Exception handling Events in a program sometimes occur at unpredictable times, I.e., apparently randomly. That is, the occurrence is an exception to the normal sequencing of events. Such events are called exceptions, and programming language constructed designed to handle these are called exception handlers. Exceptions can be created by the hardware or by software: Examples Power failure Hardware generated Printer out of paper End of page Divide by 0 End of array reached Software generated Exception handling
Testing for exceptions Although software exceptions can be tested in the code, the existence of an exception handling mechanism relieves the programmer the burden of constantly checking for this condition. Causing an exception: to raise an exception or throw an exception. Example: End-of-page Without exceptions, need to test at each print statement: print data; if end-of-page then call newPage(); With automatic exceptions, setup mechanism: [PL/I example:] On endpage begin put page; end; /* Resume execution */ can write output without checking end-page condition each time Exception handling
Implementation of exceptions Exceptions come from two sources: conditions detected by the virtual machine, and conditions generated by the semantics of the programming language. In the former case, operating system exceptions may be raised directly by hardware interrupts or traps, such as arithmetic overflow, or they may be raised in support software, such as end-of-file condition. In C, the programmer has direct access to these signals processed by the operating system. The programmer may enable an interrupt (e.g., the sigaction function in Unix, which specifies a procedure that gets invoked when the given signal is raised). Exception handling
Exceptions in ML One can throw an exception and a handler will catch the exception. (More limited than PL/I example. Need to explicitly raise an exception.): fun doDivide(a,b) = if b=0 then raise badDenominator else a/b; fun divide(a,b) = doDivide(a,b) handle badDenominator => (print “Divide error”; 0.0); Note: doDivide is within dynamic scope of divide. Semantics if exception is raised: - If no handler, end function - Check dynamic scope of executing procedures to look for appropriate handler - If handler, execute handler, then return to exception point (e.g., print message and return 0.0 as default value in above example.) Exception handling
Exceptions in C++ try clause implements exceptions. Similar to ML: try { statements . . . If b=0 throw badDenominator; } catch badDenominator {Do something;}; Propagating exceptions: If no local exception handler, who catches exception? Usually dynamic links checked for handler try statement terminates after handling exception. Exception handling
Exceptions in Ada procedure Sub is Bad_Data_Value: exception; -other declarations for Sub begin -statements for normal processing in Sub raise Bad_Data_Value -- to raise this exception exception when Bad_Data_Value => -handler for bad data values when Constraint_Error => -handler for predefined exception Constraint_Error when others => -handler for all other exceptions end; [Constraint_Error (e.g., number too large) is a built-in exception in Ada.] Exception handling
Propagating exceptions the place at which an exception occurs is not the best place to handle it a particular exception is usually defined in terms of the dynamic chain of subprogram activations each activation record needs to record those active exceptions being passed from calling procedure propagating exceptions allows a subprogram to remain as a programmer-defined abstract operation even in processing exceptions: a subprogram may interrupt its normal processing and raise an exception. to the caller, the effect of a subprogram's raising an exception is the same as a primitive operation's raising an exception if the subprogram does not handle the exception. if the exception is handled within the subprogram, then the subprogram returns in the normal way, and the caller is never aware that an exception has been raised. Exception handling
More on implementation of exceptions the language translator may insert additional instructions. For example, to detect Index_Check caused by an invalid array subscript, the translator inserts instructions at each reference to an array, such as A[I,J], to determine whether the values of I and J are within the declared bounds. Unless the hardware or operating system provides the exception checking, checking for an exception requires software simulation. Often this cost is large. For example, it may take longer to perform the subscript bounds check on A[I,J] than it does to access the element of the array. Because of this extra cost, most languages provide a means to turn off checking for exceptions in parts of the program where the programmer determines it is safe to do so [e.g., pragma Supress(Index_Check) in Ada]. Note: programmers are notoriously bad in determining when it is safe to do so. Exception handling
Assertions An assertion is a predicate that checks for an invalid value and then raises an exception: In C++: #include <assert.h> . . . assert(x,y); In C++ it is really a macro that generates: if (x>y) {/* Print error message */} (Compare assertions to pre- and postconditions of axiomatic verification in Section 4.2.4.) Exception handling