using dbus in the platform
Havoc Pennington
hp at redhat.com
Tue Oct 9 09:51:16 PDT 2007
Hi,
Simon McVittie wrote:
> syntactically valid (dbus-python had to NIH validation for that sort of thing
> because libdbus doesn't provide it).
There are old threads about adding validate_path etc. calls to the
library, I don't remember the details. I don't recall being against
adding those, though.
> I'd tend to go for NAMESPACE_try_VERB, which is quite concise, reminds
> the reader of try/catch or try/except blocks in most languages with
> exceptions, and has the right implication of "try to do this, but if you can't,
> let me know rather than panicking".
We may want to do register_object_path() differently from something like
message_set_path().
Here is the bright-line difference between "checks" (the current
return_if_fail() stuff) and DBusError: it makes sense to handle errors,
and it does not make sense to handle failed checks.
That is, the following code is not reasonable:
try {
frobate("foo");
} catch (FooIsAnInvalidArgumentToFrobateException) {
// ... um, what are you going to do here?
}
The reason it's not reasonable is that you can simply fix the app to
never cause the error. Handling an error that you caused yourself on the
previous line is just nuts.
I want to preserve this bright line - while allowing languages with
exceptions to map both cases to exceptions. This is *also* the line
between g_return_if_fail() and GError, and I think it is the rational
line between RuntimeException and checked exceptions in Java (though
many Java programmers and even official APIs mangle this completely).
For try_register_object_path(), for example, I can imagine that you have
a plugin and you want it to provide a particular object if nobody else
already has. So having a way to conditionally register the object path
makes sense.
However, for dbus_message_set_path(), I can't think of any reasonable
scenario where you pass in an invalid path. There is a corner case where
the path is provided by a user, say as a command line arg; but I think
this is a 1% case, that happens only with dbus-related utilities like
dbus-send or something, so I think it's reasonable for the utility to
validate its input. Most of the time object paths are just hardcoded in
the source code, and so having a typo in one is an app bug plain and
simple, and the right fix is to fix the typo, not to handle a DBusError.
In languages with exceptions, there's a way to "give up" and refuse to
continue - throwing the exception. So we want to do that even for app
bugs (checks). But in a C API, the convention - at least my preferred
convention, and the one matching GLib - is the one libdbus uses.
The GError docs go into some detail on the convention.
> I've done an implementation of dbus_connection_try_register_object_path and
> dbus_connection_try_register_fallback (attached).
I'll check this out later today and reply, thanks.
> Something that might be useful to adopt from GLib is that passing in a
> NULL DBusError* should be allowed, in the same way that a NULL GError*
> is allowed
This is already allowed. I designed/implemented GError, and DBusError is
simply a copy of it, with a slight difference (DBusError is on the stack).
> - it means "I don't care about any failure, probably because
> I happen to know that only OOM can happen". That way, new API can be
> provided in the more complex form only, and the caller can just pass
> NULL if they know it won't fail for non-OOM reasons.
I do not want to see this - this is why I suggested the separate header
for the "checked" variants of functions.
It is *important information* whether a function can fail or not. The
functions in libdbus that don't have a DBusError either can't fail (as
long as the API contract is met), or they can fail in only one way and
indicate that via return value alone (generally they can fail due to out
of memory only).
Right now, if you pass NULL for an error, it means "I am ignoring an
error that can in fact happen." And if you write error handlers for a
DBusError, those handlers exist for good reason.
If DBusError is returned for functions that can't fail, then those
things aren't true.
> It'd also be good to be able to avoid calling dbus_error_init() all the
> time, by providing a DBUS_ERROR_INITIALIZER macro:
>
> /* in dbus-errors.h */
> #define DBUS_ERROR_INITIALIZER { NULL, NULL, 0, 0, 0, 0, 0, NULL }
>
> /* in user code */
> DBusError error = DBUS_ERROR_INITIALIZER;
>
That might be interesting, I have to look at the code briefly to see
what the implications are though.
Havoc
More information about the dbus
mailing list