GNOME Bugzilla – Bug 694595
Support for "maybe" containers (nullable data types)
Last modified: 2018-05-22 12:10:56 UTC
The structure "GVariant" provides an interface for nullable data types. http://developer.gnome.org/glib/2.35/gvariant-text.html#gvariant-text-maybe-types A mapping seems to be missing in the class library so far. http://developer.gnome.org/glibmm/2.34/classGlib_1_1VariantBase.html https://mail.gnome.org/archives/gtkmm-list/2011-October/msg00051.html http://article.gmane.org/gmane.comp.gnome.gtkmm/25571 I imagine that an additional container type would be needed for the safe creation of "Maybe Types". It will also be eventually needed to reset an object to "nothing" after it was created with such a data type and a specific value. Would you like to reuse any implementation from a function like "g_variant_new_nothing_from_type"? https://mail.gnome.org/archives/gtk-devel-list/2013-February/msg00124.html http://article.gmane.org/gmane.comp.gnome.gtk%2B.devel.general/23167
A reply at last! The gtkmm-list message you link to, https://mail.gnome.org/archives/gtkmm-list/2011-October/msg00051.html, is part of a long thread that started with the question how to handle three-valued logic in gtkmm (false, true, or unknown). Isn't the discussion of Glib::Variant a sidetrack in that context? Glib::Variant is probably not the answer, not even with maybe types. For one thing because GVariants are immutable. From https://developer.gnome.org/glib/stable/glib-GVariant.html: GVariant instances always have a type and a value (which are given at construction time). The type and value of a GVariant instance can never change other than by the GVariant itself being destroyed. This bug report was filed almost 1.5 year after the discussion in the mailing list. In the meantime, soon after the mailing list discussion, José Alburquerque added some API to Glib::VariantContainerBase. There are still no separate classes for maybe types, but there are static Glib::VariantContainerBase Glib::VariantContainerBase::create_maybe( const VariantType& child_type, const VariantBase& child = VariantBase()); bool Glib::VariantContainerBase::get_maybe(Glib::VariantBase& maybe) const; Isn't that enough? What else do you want?
(In reply to Kjell Ahlstedt from comment #1) > There are still no separate classes for maybe types, I hope that the library can be improved here. > but there are > static Glib::VariantContainerBase Glib::VariantContainerBase::create_maybe( > const VariantType& child_type, const VariantBase& child = VariantBase()); Can this interface be used to create another "maybe instance" from a previous object? > Isn't that enough? Yes. - I tried to point a few implementation details out where I missed specific functionality. Would you like to reconsider software development challenges from my proposal?
(In reply to Markus Elfring from comment #2) > Can this interface be used to create another "maybe instance" from a > previous object? Yes, that's what it's supposed to do. Glib::Variant<some_type> var = ...; Glib::VariantContainerBase maybe_yes = Glib::VariantContainerBase::create_maybe(var.get_type(), var); Glib::VariantContainerBase maybe_no = Glib::VariantContainerBase::create_maybe(var.get_type()); > Would you like to reconsider software development challenges from my > proposal? You have probably given this "maybe stuff" more thought than I have done, or want to do. The chance that you will get what you want would improve, if you could describe it in more detail. Preferably in the form of a patch. If you don't want to be that detailed, a sketch of a class structure with prototypes of at least the most important methods would be helpful.
(In reply to Kjell Ahlstedt from comment #3) > Yes, that's what it's supposed to do. What will happen if the previous object was a maybe variant already? How should nesting of data types be handled here? > You have probably given this "maybe stuff" more thought than I have done, My suggestions might need further fine-tuning. > or want to do. I hope that the interest of the involved software developers can grow a bit around the affected details. 1. Would you like to add a base class for maybe types? 2. How do you think about my approaches for a function like "g_variant_new_nothing_from_type"? How should a corresponding member function look like?
(In reply to Markus Elfring from comment #4) > What will happen if the previous object was a maybe variant already? A maybe type is a container that can contain zero or one element. (In GVariant parlance container elements are called children.) The element of a maybe container can itself be a container, such as a maybe type. Compare with std::vector, if we restrict vectors to contain at most one element. There can be std::vector<double>, std::vector<std::vector<double>>, etc. > How should nesting of data types be handled here? Not sure I understand. Can you give an example? Or did my answer to the previous question answer this one too? > I hope that the interest of the involved software developers can grow a bit > around the affected details. I'm sure you know that most software developers here are volunteers. Anyone is welcome to contribute with ideas, and even more welcome to contribute with code and documentation. You yourself can be the most involved software developer in this case, if you like. > 1. Would you like to add a base class for maybe types? Maybe types should be represented by a special kind of container that can contain at most one element. I don't know of any such container type in C++ or glibmm. It has some similarity to pointers. A pointer can either point to no object or to one object. But as C++ programmers we're not fond of pointers, unless they're hidden in a class, are we? I guess a new container class is needed. > 2. How do you think about my approaches for a function like > "g_variant_new_nothing_from_type"? > How should a corresponding member function look like? I don't really understand what it does, and in what situation it's useful. The link to gtk-devel-list in comment 0 links to a message in a long thread. I suppose the explanation is somewhere in that thread. If you can add a link to such a message, I won't have to read all those messages. Unless there are good reasons for it, I doubt that we will add a member function that does not correspond to a function in glib.
(In reply to Kjell Ahlstedt from comment #5) > Or did my answer to the previous question answer this one too? Partly. - You acknowledged that a maybe type refers also to another data type. I imagine that you would occasionally like to limit the nesting to some degree here. How do you think about to avoid the creation of a maybe object which will contain a maybe item? > You yourself can be the most involved software developer in this case, I achieved some improvements at other places already. > if you like. Further progress will need a constructive clarification. > I guess a new container class is needed. Does such a design detail get wider consensus? Which identifiers should be selected now? Does a corresponding C++ name space make sense? > I don't really understand what it does, and in what situation it's useful. Can you follow a desire to construct an empty maybe object? > If you can add a link to such a message, > I won't have to read all those messages. How are the chances to refresh the ideas from the published patches? https://mail.gnome.org/archives/gtk-devel-list/2013-February/msg00124.html https://mail.gnome.org/archives/gtk-devel-list/2011-December/msg00018.html > Unless there are good reasons for it, I am curious if a better understanding will evolve. > I doubt that we will add a member function > that does not correspond to a function in glib. I tried to extend this library. It seems that my update suggestion got insufficient attention a while ago so that the extension will need more efforts for general acceptance.
Created attachment 302719 [details] [review] patch: Glib::Variant: Improve handling of maybe types I've added Glib::VariantContainerBase::create_null_maybe(), which I believe does what you intend to do with g_variant_new_nothing_from_type(). I don't understand why you're so anxious to have such a function in glib or glibmm, but never mind. You don't have to explain. I have not tested the new code. I (or you) need to do that. But first perhaps you want to read it, and see if it needs improvement.
Comment on attachment 302719 [details] [review] patch: Glib::Variant: Improve handling of maybe types Your addition looks interesting. Further fine-tuning: * Why did you choose a "null" in the function name when you refer to a "Nothing instance" in the corresponding comment? * I find the description of the child type handling a bit confusing. Would an other wording be more appropriate? * Is a second parameter for a default type needed? * How do you think about to reuse any other smart pointer class for base functionality? * Is the introspection of the child data type really efficient?
(In reply to Markus Elfring from comment #8) > Why did you choose a "null" in the function name when you refer to a > "Nothing instance" in the corresponding comment? Not quite sure. Probably because I was thinking of null pointers. Doesn't create_nothing_maybe() or create_maybe_nothing() look a bit funny? The glib documentation talks about "null" and "nothing" interchangeably. Perhaps the documentation should be changed. What about Creates an instance of a maybe type with a null child. Still not perfect. Can you improve it? > I find the description of the child type handling a bit confusing. Would > an other wording be more appropriate? Probably. Please suggest how it shall be changed. > Is a second parameter for a default type needed? Don't know. If anyone knows how this function is going to be used, it's you. I find your choice of default type (string) arbitrary. Why not let users choose another default type, if they don't like string? > How do you think about to reuse any other smart pointer class for base > functionality? I suppose you're thinking of std::auto_ptr or std::unique_ptr. I've recently replaced an std::auto_ptr by a plain old-fashioned pointer. (Bug 748630) std::auto_ptr is deprecated in C++11. It generates compiler warnings when people compile their application programs with gcc's -std=c++11 option. std::unique_ptr does not exist prior to C++11. I've been thinking about not using a pointer. Instead of T* m_data; use T m_data; bool m_is_empty; What do you think? It would simplify the Maybe class. No need for user-defined copy constructor, copy assignment and destructor. > Is the introspection of the child data type really efficient? Don't know. Is it important? Is this a function you expect will be called many times per second in some program?
(In reply to Kjell Ahlstedt from comment #9) > Doesn't create_nothing_maybe() or create_maybe_nothing() look a bit funny? Yes. - I can also get this impression. But I assume that we need to live with a few surprises from the reuse of such popular words. > The glib documentation talks about "null" and "nothing" interchangeably. Is the API reference documentation a bit vague there? I would prefer to achieve a consistent terminology. > Can you improve it? Do you know a technical writer who is eventually better than me? > If anyone knows how this function is going to be used, it's you. I find that you are also an experienced software developer who will recognise corresponding use cases. > I find your choice of default type (string) arbitrary. Yes. - Will an empty string be sufficient in some cases? > Why not let users choose another default type, > if they don't like string? How do you think about to provide such a selection possibility by a second function? Under which circumstances can a C++ compiler optimise an unneeded parameter away? > I've been thinking about not using a pointer. > Instead of > T* m_data; > use > T m_data; > bool m_is_empty; Would you like to make such design details configurable with specialisation of class templates? > Is it important? Yes. - I find that the introspection of the child data type needs to be really efficient. Were the affected programming interfaces improved since my initial request? > Is this a function you expect will be called many > times per second in some program? Yes. - Do you know any database applications where this can occasionally happen?
Sorry for the delay. I should have replied earlier. Anyway, this reply will disappoint you. Like I said at the end of comment 5, I'm reluctant to add API with no correspondence in glib. Your latest comment made me aware that you want a level of time-optimization beyond what is common in glib and glibmm. That made me even more reluctant to pursue this matter further. I leave this bug as it is. If you're lucky, someone else will finish the job in the future.
(In reply to Kjell Ahlstedt from comment #11) > Like I said at the end of comment 5, I'm reluctant to add API > with no correspondence in glib. Have got any better contacts to related software designers and developers so that my improvement suggestion can eventually become a bit more attractive? > Your latest comment made me aware that you want a level > of time-optimization beyond what is common in glib and glibmm. Are there still any open issues in the involved APIs for the safe and fast determination of the maybe property from the child data type?
To add to the pile... just some thoughts that might spark further discussion. I feel like the API around this could be a LOT better. It's not unusable or performance-limiting for me, but it tend towards code that hurts my eyes and brain. Initially, I just didn't intuitively understand it at all. That might be partly my fault, but I think it's also inherent in the current API: Bug 778215 I made a couple of tweaks to the docs to slightly improve matters: Bug 778219 Stuff like my examples in the last comment on that 1st bug is bearable, just about - _if_ you only need to extract the values of 1 or 2 maybe-type Variants. However, my eyes nearly began to bleed when the number became 4... so here are some helper functions I devised to mitigate the damage: template<typename T> T get_known_maybe( Glib::RefPtr<Gio::Settings> const& settings, Glib::ustring const& key ) { maybe_type maybe; settings->get_value(key, maybe); assert(maybe.get_n_children() == 1); Glib::Variant<T> variant; maybe.get_child(variant, 0); return variant.get(); } template<typename T> void set_known_maybe( Glib::RefPtr<Gio::Settings> const& settings, Glib::ustring const& key, Glib::VariantType const& type, T const value ) { settings->set_value( key, maybe_type::create_maybe( type, Glib::Variant<T>::create(value) ) ); } I'm using maybe-typed Variants only because I have a group of settings that won't exist on the very 1st run, as they are saved during quit. Therefore, I only need to check one of them to know they're all valid - and beyond that, they're "known maybes", as per the above, facetiously Rumsfeldian terminology. Is there perhaps a case for getting some helpers like this into the official API? Obviously the Settings-specific parts of it could be excised, but we could still save a lot of boilerplate at the sites using helpers like this. I've not looked deeply into the *g files yet to determine whether things could be made better with wider changes to how they work, but I'm starting by thinking about how we can provide convenience helpers around the current, baffling API.
(In reply to Daniel Boles from comment #13) > I'm using maybe-typed Variants only because I have a group of settings that > won't exist on the very 1st run, as they are saved during quit. Therefore, I > only need to check one of them to know they're all valid - and beyond that, > they're "known maybes", as per the above, facetiously Rumsfeldian > terminology. Of course, soon after this I realised that I can just have one of them be a 'maybe', and have the rest be normal ('always') variants with sane-but-never-used default values. That's easier, even if it is philosophically a bit misleading. Still, maybe the above is still worth pondering; I dunno. :)
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/glibmm/issues/11.