Re: GException notes




Karl Nelson <kenelson@ece.ucdavis.edu> writes: 
> Shouldn't that be const gchar*?
> 

Yeah, I think I did that for GConfError, good point.

> 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.
> 

I don't see a reason to support allocing the exception without using
g_exception_new(). What's the benefit? Just avoiding a strdup() which
is a pointless optimization and discourages creating a nice printf()'d
error message with additional information. It increases complexity for
no reason.
 
> 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.)
>

Global doesn't work at all unless you make it per-thread. Per-thread
global is a possibility. Note however that it doesn't gain you much;
you still have to zero or clear the global at the start of each
function, unless you require error functions to have a return code
indicating whether an error occurs.

Requiring return codes is somewhat gross; it often leads to an
unnatural API (for example gconf_get_bool() couldn't return a bool).

I think requiring a return code is a natural consequence of using a
global error object, because if you don't require them then you have
to require the error object to be cleared by the caller or the callee,
and then you lose the only real advantage of a global object (the fact
that you can ignore it). i.e. g_exception_catch() is no easier to type
than GException* exc = NULL.
 
> #define g_exception_pass() if (g_exception_is_set()) return
> #define g_exception_pass_val(X) if (g_exception_is_set()) return (X)
>

These need the word "return" in the name of them.
g_return_if_exception() or something.

Note that you can just as well have:

 #define g_return_if_exception(exc) if (exc != NULL) return

> 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.
> 

Potentially. I think it doesn't matter for backward compat because
very few glib/gtk functions actually need exceptions. I don't know how
it affects connections negatively.

>   g_exception_catch();
>   frobate(blah,blah2,NULL);
>   g_exception_try(&ferby, FerbyHandler);
>   g_exception_try(&frobate, NULL);

To me it's very unclear what is happening in this code. I can guess
what you mean, but have no real idea. It also looks like you have to
write a separate error handling routine. Compare to:

 GException* exc = NULL;

 frobate(blah, blah2, &exc);

 if (exc != NULL)
   {
      /* handle error */
      ;
   }

Here it is very transparent what's going on. To me this is a huge
benefit.


An alternative approach is to set a global error object instead of
ignoring errors whenever the user passes NULL for the GException**
argument. Then you can basically have both APIs. I'm not sure if the
functionality duplication is worth it.

I do think the global object basically works, preferring the final
function argument approach is a subjective decision.

An advantage of the GException** argument is that the API requires the
programmer to think about errors, which is IMO a good thing, and Java
does this for example (it won't compile if you don't handle or rethrow
all the exceptions a method can throw). With GException** args you
have to at least pass NULL and explicitly say you don't care about
errors.

Of course an advantage of a global object is that you can ignore
errors entirely, but I think this is at best a dubious benefit. It's
actively broken to do this within a function that can raise errors
(since you are required to clear any nonfatal errors), and it is most
likely broken in user code (because if an API raises exceptions it
should be doing so because the exceptions matter, if the exceptions
can safely be ignored it shouldn't be raising them). Ignoring errors
by passing NULL for the error object is not burdensome, and makes it
hard to accidentally ignore them.

Another advantage of GException** is its similarity to the way CORBA
works.

Havoc










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