Re: GException notes



Tim Janik <timj@gtk.org> writes:
> without setjmp/longjmp constructs, stuff1() and stuf2() will always
> be executed, no matter how hard C() and D() try to THROW things
> around.
> while havoc is about to jump up at this point to tell that B() is
> incredibly wrong coded because it doesn't CATCH after calling C(),

It _is_ wrong.

> this is exactly the situation you'll find most often in gtk+ code.
> consider A() some user function that causes a signal emission in
> its TRY block, B() being signal_emit() and C() and D() being user
> defined handlers.
> 

You simply can't do errors in that case. You can't have signal
handlers add exceptions to a function like gtk_button_clicked(); you
would have to check for errors after _every_ gtk_signal_emit() in all
of GTK+. No thanks.

KISS - errors are for simple stuff, like gdk_pixbuf_new_from_file(),
GConf, pango_do_whatever_pango_does(). Introducing errors into GTK's
GUI stuff and signal handlers just makes life hellishly overcomplex by
requiring you to check errors after _every_ line of GTK code.

Furthermore it muddles your ability to know if a function failed
because it creates random side-effect errors like UNIX errno. 
i.e. you call gdk_pixbuf_blah_blah, it somehow invokes a callback and
causes an error, even though the function succeeded and returns
non-NULL. So then you have this weird spurious error in your error
stack that you almost 100% likely don't care about.

Perhaps I am misunderstanding, can you give a sample use case where
you want a user signal handler to add an error?

> usuall flow control of a program, i think the name "exceptions" is
> majorly misleading here.
> 

GError is shorter anyway so I'm in favor of it.

> rather, something like a global error entity that could be set would
> be more appropriate, but still doesn't satisfyingly solve the above
> case where C() and D() have error conditions that we might want to
> see handled by A().
> 

The single global error object is _broken_ in that case, not merely
unsatisfactory. The stack is also _broken_ unless you have a return
value or other mechanism to distinguish "fatal errors" from "side
effect errors that some callback happened to set."

i.e. you are not answering the question: how do you know if the
routine failed. No error solution works if you can't answer this.

As far as I can tell the only way to do that in your scheme is to
switch on error code and know which ones are fatal and which
aren't. But what if C() having "File not found" is nonfatal and D()
having "File not found" is fatal. You can't tell which routine caused
the file not found that is actually in the error stack.

Piling up errors is broken. You have to handle or pass up each error
immediately. If you can't avoid pileups, as in signal handlers, you
can't use a generic error mechanism, you are going to need some
situation-specific code. Most likely 95% of the time you want to
handle the error in the signal handler that caused it.

> so to top that, the basic idea to initially start out on should be
> soemthing like an error stack that can be accumulated in callbacks
> and be (selectively) handled/discarded at higher function levels that
> care.
> 

You need to know if the overall routine failed or not to selectively
handle errors. The stack gives you no way to know.

Again, one way to do this is with a return value; another might be to
have two global objects, the stack and some sort of "fatal error
happened" indicator, but then you are approaching Extreme Complexity.

> so suppose we are actully talking about some kind of error stack here,
> there's another interesting thing that would be nice to have, but has
> only been slightly touched by havoc's initial proposal:
> type variant errors
> 

Good point, I think a simple user data field would be good enough for
a start here.
 
> while this may not exactly be what havoc and karl had in mind originally
> (and doesn't come with as much syntactic sugar), it actually comes far
> closer to our needs in a strongly callback-influenced environment.
> and noticably isn't by any means more complex, though still allowes for
> a far more flexible handling mechanism.
> 

It's significantly more complex.

  - you have to switch on error object type in addition to error code
    and error module
  - you have to iterate over the stack of errors
  - together the above two mean two more levels of nesting after 
    every error function
  - functions have to have a return value to indicate fatal failure,
    or you need an additional object or flag to indicate that
  - it's significantly harder to display a stack of errors to the 
    user than a single string
  - almost certainly in my experience with GConf only one of the 
    errors is the "real" error that should be displayed to the user
    or handled programmatically

> interesting aspects that should be furtherly investigated are whether
> we really want the error list to be stack with FIFO behaviour (LIFO
> could be interesting here as well), and whether it'd make sense to be
> able to provide priorities or fatality flags for distinct errors.
> 

Fatality flags potentially allow you to distinguish fatal failure, 
with the cost of yet more complexity.

if (errors_exist)
  foreach error
    if fatal 
      switch type
        switch module
          switch code
    else 
      switch type
        switch module
          switch code

And for each leaf node in the switch tree you need
error-object-specific code to print the error since you can't just do
a generic err->str, and you need a default: case which does
who-knows-what because you could get any error whatsoever due to user
callbacks.:-) And what does it mean if a user callback sets a fatal
error but the function that resulted in calling the user callback does
not? Then you know "this immediate function worked but some unknown
callback did not." No thanks! 
 
> not to mention varargs functions which want to report errors, but
> had to break with that convention.
>

A minuscule problem compared to your Extreme Complexity, Tim :-)

Havoc



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