[RFC] Gnome2::GConf error handling



Hi all.

I've started looking at error handling in GConf, and I need some insight
from all the users of this list, especially from the perspective of users
of GConf under languages different from Perl.

* Background

As far as I understood from reading the API, and from testing it in C,
error handling in GConf is splitted between two options, both based on
the GError structure; every function has a parameter that could contain
a pointer to that structure.  If a user does indeed pass a pointer to an
address of a GError struct, and the function fails, that structure is
filled, and the programmer may show the error by accessing to the
"message" public member, e.g.:

  GError *err = NULL;
  GConfClient *client = gconf_client_get_default ();
  gconf_client_set_string (client, "/test/app/key", "test", &err);
  if (err) {
          fprintf (stderr, "Error (key '/test/app/key'): %s", err->message);
          /* ... */
  }

The "error" signal is also emitted, and the default error handler is
invoked; if a callback is attached to that signal, the programmer may
stop the propagation of the "error" signal, thus preventing the
invocation of the default error handler; the programmer may even change
the default error handler with a function that himself supplies, using
the gconf_client_set_default_error_handler function.  As you can see,
the error handling is highly customisable by the programmer perspective.

It's not the end, though.  If the programmer wants a finer grained error
handling, he could pass NULL to a function, and connect a callback to
the "unhandled_error" signal, which is emitted in this case (the "error"
signal is emitted anyways, but the programmer may want to stop that
inside the callback, thus preventing the chain to reach the default
error handler). E.g.:

  GConfClient *client = gconf_client_get_default ();
  g_signal_connect (G_OBJECT (client), "unhandled_error", on_uerror, NULL);
  gconf_client_set_string (client, "/test/app/key", "test", NULL);
  
  /* ... */
  

* Summary & Considerations

- A programmer whom does not care about error handling could pass either
  a NULL or a pointer to GError address: in either case the default
  error handling will take care of any (eventual) error that could occur.

- A programmer that wants a generic error handling could pass a pointer
  to a GError location, and then check that structure, or listen to the
  catch-all "error" signal (which propagates the GError to any callback
  attached to it).

- A programmer whom wants a per-function error handling, will pass NULL
  to those functions he wants to handle, and then listen to the
  "unhandled_error" signal.

- At any time, the programmer whom wants to change the default error
  handler function, which could be used for every error or as a fallback
  for any generic error which does not need a special handler, could
  do it using the appropriate function.

* Situation in the Perl binding

Actually, every fallible function that has the GError parameter in its
signature, has a GError silently passed to it, and aborts on failure
using croak(); it is completely transparent from the Perl programmer's
point of view, and it's good for debugging.  This is, as a matter of
fact, an acceptable compromise since the programmer may listen to the
"error" callback (as soon as I modify it to pass the Perl equivalent of
the GError structure[1]) or change the default error handler (this is
yet to be implemented).

* Possible improvements

Given the fact that the programmer might want to handle errors on a
per-function basis, and that using the error function with an
if...elsif...else check would be awkward, especially since whe have the
"unhandled_error" signal that might be used, here's my RFC: every
fallible method of Gnome2::GConf::Client will have an optional argument,
which will be used to pass an error handler sub; internally, the binding
will provide to connect that sub to the "unhandled_error" signal, thus
removing the need for the programmer to connect a that sub to the
"unhandled_error" signal; e.g.:

  my $client = Gnome2::GConf::Client->get_default;
  my $str = $client->get_string("/test/app/key", sub {
          print STDERR "Error while retrieving data from /test/app/key\n";
      });

Another way of handling that would be passing a boolean parameter, which
would be internally checked for wheter passing or not a GError to the
bound function, and letting the programmer explicitly connect a callback
to the "unhandled_error" signal, e.g.:

  $client->signal_connect(unhandled_error => sub {
          my $err = shift;
          print STDERR "Error: %s\n";
      });
  my $str = $client->get_string("/test/app/key", TRUE);


The first solution is some kind of "semantic sugar", and, in my opinion,
is more perlish than the second one, but to me are pretty much the same:
I'm very open minded about this question.

So, I'd like to hear every comment you might have, and your alternative
solutions, if any, about this.

+++

[1] I've been thinking of supplying directly the string of the error
inside the calbback signature, but I've checked yet if and how this is
done inside gtk2-perl at this moment.

Regards,
 Emmanuele.

-- 
Emmanuele Bassi (Zefram)       [ http://digilander.libero.it/ebassi/blog ]
GnuPG Key fingerprint = 4DD0 C90D 4070 F071 5738  08BD 8ECC DB8F A432 0FF4



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