GNOME Bugzilla – Bug 644146
Dynamic cast of Variants
Last modified: 2011-09-20 18:48:04 UTC
In some methods, for example when handling setting a property for a D-Bus interface (SlotInterfaceSetProperty in Gio::DBus::InterfaceVTable), we receive a parameter of type Glib::VariantBase with a real type (for example Glib::Variant<int>) which depends on the context of the call of the method. We are therefore naturally enclined to do a dynamic cast, something similar to the cast_dynamic function of Glib::RefPtr. I think that such a functionnality would be helpful for Variant but I'm not sure that it will be easy to implement it...
Well, yes, VariantBase should not be used for anything but an output parameter, so this API makes no sense: http://git.gnome.org/browse/glibmm/tree/gio/src/dbusconnection.hg#n1027 I'll remove that API if we can't think of a better way to do it.
Indeed, after having investigated more precisely the DBus API, I found that the DBus specifications of the method Set() that InterfaceVTable try to wrap is: org.freedesktop.DBus.Properties.Set (in STRING interface_name, in STRING property_name, in VARIANT value); In this prototype, the variant value is of type "v", which should be useful for giomm since it can be represented by a Variant<VariantBase> type. Unfortunately, gio does not send directly the variant received (of type "v") but the variant contained by the variant received. Thus this variant can be of different types. Peharps, that a solution would be to "re-embeded" the variant in a variant of type "v" before calling the slot "SlotInterfaceSetProperty" and to redeclared the type of the slot by something like: typedef sigc::slot< bool, const Glib::RefPtr<Connection>&, const Glib::ustring&, const Glib::ustring&, const Glib::ustring&, const Glib::ustring&, const Glib::Variant<Glib::VariantBase>& > SlotInterfaceSetProperty; ?
Created attachment 183088 [details] [review] Modify prototype of SlotInterfaceSetProperty This patch show what the changes could be if we modify the VariantBase parameter of SlotInterfaceSetProperty to a Variant<VariantBase>.
Created attachment 183089 [details] An example using SlotInterfaceSetProperty Here is a (long) example which is a work in progress. The interesting part is the method on_set_property() of main_server.cc which is linked to InterfaceVTable.slot_set_property.
(In reply to comment #2) > Indeed, after having investigated more precisely the DBus API, I found that the > DBus specifications of the method Set() that InterfaceVTable try to wrap is: > org.freedesktop.DBus.Properties.Set (in STRING interface_name, > in STRING property_name, > in VARIANT value); > In this prototype, the variant value is of type "v", which should be useful for > giomm since it can be represented by a Variant<VariantBase> type. I don't really understand that. What's the point of a variant that contains a variant? In the handle_set_property() on line 229 of the example here, it gets a string directly out of the variant, which seems to contradict your theory. http://library.gnome.org/devel/gio/unstable/GDBusConnection.html I said: > VariantBase should not be used for anything but an output parameter, Not that this is not strictly true. It would be fine for a set_something(const VariantBase& value), if we just passed that GVariant to a C function. It's just unpleasant to expect C++ code to deal wit a VariantBase. So I maybe led you astray. Maybe we really need to have some generic way to cast from a VariantBase to a specific Variant<>. It doesn't feel impossible.
(In reply to comment #5) > I don't really understand that. What's the point of a variant that contains a > variant? > These variants are variants of type "VARIANT" of the DBus specification. These are variants of type "v" in glib. They are used, for example, in dbus to allow methods to have some "generic" parameters. These variants can contain values (variants) of different types. I suggest to use this type of variants here as a workaround to the fact that we cannot obtain the real type of a Variant from a VariantBase whereas it is possible to obtain a variant contained in a Variant<VariantBase> with the right type. > In the handle_set_property() on line 229 of the example here, it gets a string > directly out of the variant, which seems to contradict your theory. > http://library.gnome.org/devel/gio/unstable/GDBusConnection.html > Yes, but this is because the handler in gio does not match exactely the dbus specification. Indeed, in gio, when we receive a call to the method set_property(), the parameters are extracted with a get("ssv", ...) which leads to extract the value contained in the variant of type "v" and this is this value (in the example, a variant of type "s") which is passed to the handler. > I said: > > VariantBase should not be used for anything but an output parameter, > > Not that this is not strictly true. It would be fine for a set_something(const > VariantBase& value), if we just passed that GVariant to a C function. It's just > unpleasant to expect C++ code to deal wit a VariantBase. > > So I maybe led you astray. > > Maybe we really need to have some generic way to cast from a VariantBase to a > specific Variant<>. It doesn't feel impossible. Yes, if we could have a cast this would resolve our problems and simplify the wrap of the dbus API.
Created attachment 183381 [details] [review] A cast function for Variant Here is a first attemp for a cast operator for Variants. I'm not really convinced that this cast function is well designed but it shows at least that dynamic cast can be defined for variants.
(In reply to comment #5) > I said: > > VariantBase should not be used for anything but an output parameter, > > Not that this is not strictly true. It would be fine for a set_something(const > VariantBase& value), if we just passed that GVariant to a C function. It's just > unpleasant to expect C++ code to deal wit a VariantBase. And I think I am even more wrong. Gio::VariantBase does seem to be copyable and that seems to be OK. It's Glib::ValueBase that shouldn't be used like that. And yes, we do then need some way to dynamic_cast it.
> These variants are variants of type "VARIANT" of the DBus specification. These > are variants of type "v" in glib. They are used, for example, in dbus to allow > methods to have some "generic" parameters. These variants can contain values > (variants) of different types. I suggest to use this type of variants here as Ah, so it's just that DBus sv (string, variant) parameters would be Variant<string>, Variant<Variant> in GDBus, because GDBus puts all parameters in a Variant. We should probably add a hint about that to the Variant<VariantBase> documentation.
This seems fairly sane so I've pushed it, with an extra explanatory note in the commit message from me: http://git.gnome.org/browse/glibmm/commit/?id=4af5c32ac1c325a63d89e5a35ca8647c4a4bb908 I notice that the Variant<VariantBase> workaround that you mention above does not seem to be involved, which I'm glad about.
(In reply to comment #10) > This seems fairly sane so I've pushed it, with an extra explanatory note in the > commit message from me: > http://git.gnome.org/browse/glibmm/commit/?id=4af5c32ac1c325a63d89e5a35ca8647c4a4bb908 > > I notice that the Variant<VariantBase> workaround that you mention above does > not seem to be involved, which I'm glad about. Yes, since we have now dynamic cast, we do not need this ugly workaround.
About this bug, does that mean that we can now return Glib::VariantBase in cases where the variant type of the return is not known (an example would g_action_get_state_hint()[1] and g_action_get_state()[2]) or should output parameters still be used? [1] http://developer.gnome.org/gio/stable/GAction.html#g-action-get-state-hint [2] http://developer.gnome.org/gio/stable/GAction.html#g-action-get-state
Yes, you can and should do that.