After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 694595 - Support for "maybe" containers (nullable data types)
Support for "maybe" containers (nullable data types)
Status: RESOLVED OBSOLETE
Product: glibmm
Classification: Bindings
Component: general
2.35.x
Other All
: Normal enhancement
: ---
Assigned To: gtkmm-forge
gtkmm-forge
Depends on:
Blocks:
 
 
Reported: 2013-02-24 16:27 UTC by Markus Elfring
Modified: 2018-05-22 12:10 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
patch: Glib::Variant: Improve handling of maybe types (9.14 KB, patch)
2015-05-01 11:31 UTC, Kjell Ahlstedt
none Details | Review

Description Markus Elfring 2013-02-24 16:27:21 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
Comment 1 Kjell Ahlstedt 2015-04-26 11:21:54 UTC
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?
Comment 2 Markus Elfring 2015-04-26 19:00:17 UTC
(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?
Comment 3 Kjell Ahlstedt 2015-04-27 08:36:25 UTC
(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.
Comment 4 Markus Elfring 2015-04-27 11:50:34 UTC
(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?
Comment 5 Kjell Ahlstedt 2015-04-28 08:54:53 UTC
(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.
Comment 6 Markus Elfring 2015-04-28 10:00:38 UTC
(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.
Comment 7 Kjell Ahlstedt 2015-05-01 11:31:38 UTC
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 8 Markus Elfring 2015-05-01 19:08:28 UTC
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?
Comment 9 Kjell Ahlstedt 2015-05-03 14:45:45 UTC
(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?
Comment 10 Markus Elfring 2015-05-03 18:20:56 UTC
(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?
Comment 11 Kjell Ahlstedt 2015-06-07 14:10:22 UTC
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.
Comment 12 Markus Elfring 2015-06-07 17:55:47 UTC
(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?
Comment 13 Daniel Boles 2017-05-14 14:07:28 UTC
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.
Comment 14 Daniel Boles 2017-05-14 14:14:44 UTC
(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. :)
Comment 15 GNOME Infrastructure Team 2018-05-22 12:10:56 UTC
-- 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.