Path: utzoo!utgpu!water!watmath!clyde!att-cb!att-ih!gargoyle!oddjob!nucsrl!morrison From: morrison@eecs.nwu.edu (Vance Morrison) Newsgroups: comp.lang.c++ Subject: Proposal for Exceptions for C++ Message-ID: <8180006@eecs.nwu.edu> Date: 28 Mar 88 22:23:55 GMT Organization: Northwestern U, Evanston IL, USA Lines: 214 A PROPOSAL FOR ADDING EXCEPTION HANDLING TO C++ I have heard that exception handling for C++ is "in the thinking about stage". Unfortunately, not having exceptions is severely camping my style and so I am writing a preprocessor that adds exception handling to C++. It would be VERY nice if the exception handling scheme that I implement be very similar to the type eventually implemented in the language (when that happens). Thus I would like to submit my proposal to the net to see what everyone thinks. This proposal is at present very informal. After the first round of discussion, we may want to formalize it. STRATEGY: C and C++ derive their strength from the fact that the language itself is small. Instead, most of the power in C and C++ comes from library routines. This give the programmer much more flexibility in extending the language and also simplifies porting the language. Thus I propose changing the language as little as necessary to support exceptions. EXCEPTIONS: Exceptions allow the programmer to bypass the normal flow of control of the program. By raising an exception, a procedure can signal an abnormal condition that the procedure is not prepared to handle. Raising an exception thus initiates a search up the call stack for a routine that can "handle" the exception. If an exception handler is found, control is handed to it. If no handler is found, a "last chance" handler is executed which usually prints out an error message, produces a stack trace and aborts the program. I will not go into the merits of exceptions, but I will state that they are indispensable for reusable modules because they give default error handling to the module designer, while allowing the module user to change error handling. PROPOSAL: Only three changes to the syntax of the language are necessary 1) Add the statement '_raise' to the language: 1) Add the statement 'resume' to the language: 2) Any statement can now be followed by the following construct catch For example i = j/k; catch { printf("divide by zero error\n"); } As one might expect, '_raise' raises an exception, while 'catch' declares a handler for a statement. Thus whatever statement precedes 'catch' is "protected", in the sense that if any exception is raised in the protected statement, control is given to the statement after 'catch'. For example err() { if () _raise; } main() { err(); catch { printf("error"); } printf("done\n") } In this example the statement 'err();' is protected, so that if an exception is raised in 'err();' then "error" is printed. After the statement after 'catch' is executed, _raise IS IMPLICITLY CALLED. Thus in the above example after "error" is printed _raise is implicitly called and the last chance handler is called. Thus "done" is NEVER printed out. To provide the facility to return to normal flow of control the 'resume' statement is use. For example main() { err(); catch { printf("error"); resume; } printf("done\n") } Now if an exception is raised in 'err()' then "error" will be printed and control will be resume at 'printf("done");'. This behavior is deliberate. The reasoning is that error conditions should NEVER be ignored by default. Thus if the error is to be ignored (that is normal flow of control is to resume), the programmer must explicitly say so by using the resume statement. SYNTACTIC AMBIGUITIES In the following example for(i=0; i< 10; i++) { printf("%d\n", err()); } catch { printf("error\n"); resume; } Is the 'catch' statement only protecting the printf, or the whole for(;;) statement? Here we define it to be just the printf statement. If the other meaning was desired, the syntax would be { for(i=0; i< 10; i++) { printf("%d\n", err()); } } catch { printf("error\n"); resume; } FUNCTION BODIES A function body is a legal statement to catch thus int main() { err(); return(0); } catch { printf("err\n"); return(-1); } Is legal and protects the whole function body. Note that 'return' is a legal statement in a catch clause, and is another way to escape from a catch clause (goto will also work). MAKING IT USEFUL The changes to the language were designed to be minimal. In this raw form it is not very useful since only one unnamed exception can be raised. But using just this simple basis, I have designed a module that implements named exceptions with parameters in C++. Below is an example of a module with three exceptions FILE_N_FOUND, FILE_NUMBERS, and FILE_ERROR. In the main program the function 'file_call' is protected so that if FILE_ERROR or FILE_N_FOUND is raised, they are caught and their parameters examined. All other exceptions will be reraised and the last chance handler will be invoked. I will not explain the workings of my exception module here. This example is only meant to show that a sophisticated exception module can be built from the simple tools I propose. SO WHAT DO YOU THINK???? Vance Morrison morrison@accuvax.nwu.edu morrison@nuacc.bitnet ****** GENERIC MODULE HEADER FILE ********************************* extern void file_call(); /* declare FILE_N_FOUND with a parameter 'name' of type 'char_ptr' */ DECLARE_EXCEPTION_1(FILE_N_FOUND, char_ptr, name); /* declare FILE_N_FOUND with a parameter 'name' of type 'char_ptr' and a parameter 'number' of type 'int' */ DECLARE_EXCEPTION_2(FILE_NUMBERS, char_ptr, name, int, number); /* declare FILE_N_FOUND with no parameters */ DECLARE_EXCEPTION_0(FILE_ERROR); ****** GENERIC MODULE ********************************************* #include "exception.h" #include "example.h" /* the string given here will be printed out using "printf" and the parameters (in order) by the default handler */ CREATE_EXCEPTION(FILE_N_FOUND, "File name '%s' not found"); CREATE_EXCEPTION(FILE_ERROR, "Generic file error"); CREATE_EXCEPTION(FILE_NUMBERS, "File name '%s' has error at number '%d'\n"); void file_call() { FILE_NUMBERS.raise("myfile", 10); } ****** PROGRAM USING MODULE **************************************** #include #include "exception.h" #include "example.h" main() { /* call file_call and catch the FILE_ERROR FILE_NUMBERS */ file_call(); catch { if (FILE_ERROR.is_raised()) { printf("caught file error\n"); resume; } if (FILE_NUMBERS.is_raised()) { printf("caught file number error with param %d\n", FILE_NUMBERS.number()); resume; } } printf("done\n"); }