Re: Signals, GErrors and Introspection



On Sat, Feb 19, 2011 at 12:14:29AM -0500, Matthias Clasen wrote:
 
> GError has a boxed type already:
> 
> http://library.gnome.org/devel/gobject/2.27/gobject-Boxed-Types.html#G-TYPE-ERROR:CAPS

Right, I didn’t see that at first because my local copy of the API
documentation was outdated.

However, it doesn’t really solve my problem: now that I have changed the
marshal definition used by the input-request signal to

	BOOLEAN:BOXED

and the GType of the relative parameter to G_TYPE_ERROR in the signal
definition, the .gir file looks a little better:

	<glib:signal name="output-request">
	  <return-value transfer-ownership="none">
	    <type name="gboolean"/>
	  </return-value>
	  <parameters>
	    <parameter name="object" transfer-ownership="none">
	      <type name="gchar"/>
	    </parameter>
	    <parameter name="p0" transfer-ownership="none">
	     <type name="GObject.Error"/>
	    </parameter>
	  </parameters>
	</glib:signal>

but at the end of the day it doesn’t really matter since the library
segfaults as soon as the signal is emitted, because the signal handler
expects a GError** and the unboxed value is a GError*.

I tried to work around it by making the signal handler accept a GError*:
this way the segfault goes away, but I no longer have a memory location
to store the error; not to mention the handler signature looks weird.

Where do I go from here? I’m starting to think my use–case is really not
supported by GLib; at the same time, I believe signal handlers that can
fail, such as the ones I’m using, should be allowed to use a GError to
report the exact reason of the failure.

One workaround I can think of is adding to GLib a new boxed type,
G_TYPE_ERROR_LOCATION, which can be used to store a GError**. That should
do the trick.

On the other hand, it doesn’t look so nice. In fact, the whole GError API
feels a bit alien to the rest of GLib, with the requirement of passing
around double pointers most of the time and the messed–up namespacing.

What about creating a new error type (or a new API for GError — I guess it
would be possible to make compatible additions to the current API, but it
would take a lot of care to make sure both APIs are compatible) which is
more similar to the rest of the GLib APIs?

Something like a GException or GFailure. When you need to call a function
that can fail, you do something like this:

	GException *ex;
	gboolean success;

	ex = g_exception_new ();

	success = function_that_can_fail (ex);

	if (!success) {

		g_warning ("Call failed: %s",
		           g_exception_get_message (ex));
	}

	g_exception_free (ex);

Of course you wouldn’t need to allocate a new GException for every
function you call, you could just create a single GException and clear
its state between calls:

	GException *ex;

	ex = g_exception_new ();
	function_that_can_fail (ex);

	g_exception_clear (ex);
	another_function_that_can_fail (ex);

	g_exception_free (ex);

If you are not interested in the exact error, you could still pass in a
good’ol NULL pointer; we just need to make sure all g_exception* functions
do nothing when such a pointer is passed.

The only missing piece would be to have a way to identify a GException that
contains a failure report from a cleared one, something like

	GException *ex;
	gboolean success;

	ex = g_exception_new ();
	g_assert (!g_exception_contains_error (ex));

	success = function_that_always_fails (ex);
	g_assert (!success);
	g_assert (g_exception_contains_error (ex));

	g_exception_clear (ex);
	g_assert (!g_exception_contains_error (ex));

	g_exception_free (ex);

Now there is no need, for a function that reports errors via GException,
to allocate its own errors, unless of course the function calls some other
function that reports failure only by setting a GException. I believe the
number of such functions in the GNOME stack to be pretty low, because not
returning FALSE or NULL on error is bad practice anyway.

By the way, this new error type could have all its fields private, with
dedicated accessor methods like g_exception_get_message, and with coherent
namespacing.

As you can see, I think the GError API is a really good one: if I were to
design a new error reporting API (which I kinda just did ;) I would keep
most things the way they are now.

I believe this new API would be a little easier to learn and use, both
because there is less pointer dereferencing going on and because it looks
and feels like all the other APIs in the GNOME stack.

The downside would be the need to allocate a GException even if the called
function does not fail, which is mitigated by the fact that a single
GException can be used for any number of possibly–failing function calls.

What do you think?

-- 
Andrea Bolognani <eof kiyuko org>
Resistance is futile, you will be garbage collected.

Attachment: signature.asc
Description: Digital signature



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