Re: GException notes




> Concrete proposal
> ===
> 
> My concrete proposal for GException would be to basically copy the
> GConf/Pango system which seems to work well in practice.
> 
> glib would require an additional feature, namely the ability to
> distinguish between exceptions created by various modules.
> 
> struct _GException {
>   GQuark module; /* some sort of identifier for each module, 
>                     still unclear how this works */
>   gint num;      /* errno-style code, defined as an enum in 
>                     each module */
>   gchar *str;    /* human-readable description string */
> }

Shouldn't that be const gchar*?

Here I would suggest that Exceptions are Objects in a sense and
thus should have a dtor.  The dtor is something as simple as 

typedef void (*GExceptionDtor)(GException* exp);

This pointer would then be in the Exception itself.  

Thus if the memory was allocated by malloc, new, g_new, or
static for the str all could be handled properly.

 
> To get an idea of the API, look at gconf/gconf/gconf-error.[hc] and
> some of the uses of it throughout GConf. Some highlights:
> 
>  - functions that raise exceptions take GException** as their final
>    argument. If NULL is passed for this argument, then the caller
>    wants to ignore errors and no errors are reported. If a valid 
>    pointer is passed, it should point to a GException* initialized
>    to NULL. 
> 
>  - If and only if a fatal error occurs, an exception is placed in this
>    GException** location
> 
>  - Caller must check whether the error was set, and free the
>    GException if so (unless NULL was passed to ignore errors)
 
> Sample application usage:
> 
>   GException *exc = NULL;
> 
>   frobate(blah, blah, blah, &exc);
> 
>   if (exc != NULL) 
>     {
>        fprintf(stderr, _("Oops: %s"), exc->str); /* or switch (exc->num) */
>        g_exception_destroy(exc);
>        exc = NULL;
>     }

I don't understand the need to actually pass the exception pointer.
Another valid solution would be to have a global (or thread keyed
global.)

Interface....

void g_exception_catch ();  /* sets global handling on */
void g_exception_set (key, const gchar*,...);  
        /* set exception, destroys current if set */
void g_exception_set_static (key, const gchar*);
void g_exception_set_full (key, const gchar*, GExecptionDtor);
gint g_exception_try(key, Handler);  /* clears exception */
gint g_exception_is_set();           /* indicates an exception */  

#define g_exception_pass() if (g_exception_is_set()) return
#define g_exception_pass_val(X) if (g_exception_is_set()) return (X)

The exception if not handled is cleared by the next set so
no need to worry about memory leaks.  The dtor function allows
static strings of allocated memory to be used.  

A threadsafe private date can be used so that multiple threads can 
have independent exceptions.

Basically, I am asking why it needs to be passed at all?  After
all with a thread safe global you can write code like this....

int 
frobate(gint blah, gint blah2, gint blah3)
{
   if (!do_sys_stuff())
     {
       /* key is frobate itself for this exception */ 
       g_exception_set(&frobate, _("Error do_sys_stuff fail %s"), errno);
       return FALSE;
     }
   /* ... */
   ferby();
   g_exception_pass_val(FALSE);  /* throw up to next layer */
   
   /* ... */
   return FALSE; 
}

void 
use_frobate(gint blah, gint blah2)
{

   g_exception_catch();
   frobate(blah,blah2,NULL);
   g_exception_try(&ferby, FerbyHandler);
   g_exception_try(&frobate, NULL);
  
   /* other wise the exception will be destroyed on the next catch */
}

It seems to me that adding lots of exception pointers to the end
of functions will just make life very hard, especially for connections
and backward compatibility.

--Karl  




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]