meeting log January 30, 2001

Tyson Dowd trd@cs.mu.OZ.AU
Fri, 2 Feb 2001 14:14:38 +1100


On 31-Jan-2001, linas@linas.org <linas@linas.org> wrote:
> 
> 
> I have not read the whole of this log yet.  But the following caught my
> eye, and I have to address dres' reservations:
> 
> An error stack is about as close as you can come to having exceptions in
> C.  Here's how it works.  (This example uses macros, please pardon the
> sin)
> 
> 
> typedef enum { BadDog=23, ...} ErrType;
> 
> ErrType pop_error(void);
> void push_error(ErrType);
> 
> void some_low_func (..) 
> {
>    if(something bad) { THROW (BadDog);  }
> }
> 
> void some_user_func(..)
> {
>    TRY {
>      some_low_func();
>    }
>    CATCH {
>       case BadDog:
>           printf ("Bad Dog! Sit in the corner!!!\n");
>           break;
>    }
> }

Exceptions also involve more complicated control transfer.  Consider:

/* this is the same as your function */
void some_low_func (..) 
{
	if(something bad) { THROW (BadDog);  }
}

/* a new function in the middle */
void some_mid_func (..) 
{
	...
	some_low_func();
	...
	(other code, possibly throwing different exceptions)
	...
}

void some_user_func(..)
{
     TRY {
	some_mid_func();
     }
     CATCH {
	case BadDog:
	    printf ("Bad Dog! Sit in the corner!!!\n");
	    break;
     }
}

You have to transfer control from the exception in some_low_func through
some_mid_func into some_user_func.  some_mid_func might do arbitrary
amounts of computation after calling some_low_func, so you can't rely on
it to return to some_user_func to trigger the exception catch clauses
without writing explicit code to do this, or putting a TRY/CATCH in
every function.

You actually need to use setjmp/longjmp to get this to work like
C++/Java exceptions.  `return' is not flexible enough to implement
exceptions in this manner.

> and the 'magic macros' that make this work:
> 
> #define THROW(ERR)  { push_error(ERR); return; }
> #define TRY  /* no-op */
> #define CATCH {ErrType e;  while (e=pop_error()) { switch (e) { 

This is still pseudocode, but something like:

/* try: add a new jump_buf to the stack */

#define TRY 
	{
		push_new_jump_buf_onto_error_stack();
		if (setjmp(error_stack.jump_buf) == 0) {

/* catch: must directly follow a try, removes the jump_buf from the stack
if the try succeeds, otherwise it provides the else case to setjmp,
which handles any errors that get to here. */

#define CATCH
			pop_jump_buf_from_error_stack();	
		} else {
			pop_jump_buf_from_error_stack();	
			ErrType current_exception;
			while (current_exception = pop_error()) { 
				switch (e) { 

/* endcatch just closes off the braces, and if the catch didn't handle the
error then it re-throws it. */

#define ENDCATCH
				default:
					RETHROW();
				}
			}
		}
	}


/* throw: just puts the error on the error stack and then goes to the
topmost jump buf. */

#define THROW(ERR)  
	{ 
		push_error(ERR); 
		longjmp(error_stack.env, 1);
	}

/* rethrow: throws the current exception again */
#define RETHROW
	{	
		throw(current_exception)
	}

I haven't tested this (but I can if you want to use it).

> I've got some parens matching problems here, and its a little
> oversimplified, but its hopefully obvious now that C++/Java exceptions
> are nothing more than an error stack with some syntatic sugar.
> 
> So dres: you said you wished for C exceptions? 

-- 
       Tyson Dowd           # 
                            #  Surreal humour isn't everyone's cup of fur.
     trd@cs.mu.oz.au        # 
http://www.cs.mu.oz.au/~trd #