Thread overview
Why does std.variant not have a tag?
Nov 04, 2012
evansl
Nov 05, 2012
Robert Jacques
Nov 05, 2012
Johannes Pfau
Nov 05, 2012
evansl
Nov 05, 2012
Robert Jacques
Nov 05, 2012
evansl
Nov 05, 2012
Era Scarecrow
November 04, 2012
  http://dlang.org/phobos/std_variant.html

says:

 This module implements a discriminated union type (a.k.a. tagged union,
algebraic type).

Yet, the wiki page:

  http://en.wikipedia.org/wiki/Tagged_union

says:

  a tag field explicitly indicates which one is in use.

and I don't see any indication of a tag field in the std_variant.html page.  Another wiki reference:

  http://en.wikipedia.org/wiki/Disjoint_union

is more explicit because it pairs the tag with the value:

  (x,i)

where x is the value and i is the tag.

One reason for an explicit tag is that the bounded types may contain the same type twice.  This has lead to problems in boost::variant as evidenced by the post:

  http://article.gmane.org/gmane.comp.parsers.spirit.general/17118

In addition, both variant and tuple have a common part, a metafunction mapping from a tag to a type; hence, this same common part could be used to implement both tuple and a tagged variant.

A variant which actually contained a tag field I think would be more general in that it would allow duplicate types among the bounded types just as a tuple's bounded types can contain duplicate types.

-regards,
Larry

November 04, 2012
On 05-11-2012 00:31, evansl wrote:
>    http://dlang.org/phobos/std_variant.html
>
> says:
>
>   This module implements a discriminated union type (a.k.a. tagged union,
> algebraic type).
>
> Yet, the wiki page:
>
>    http://en.wikipedia.org/wiki/Tagged_union
>
> says:
>
>    a tag field explicitly indicates which one is in use.
>
> and I don't see any indication of a tag field in the std_variant.html
> page.  Another wiki reference:
>
>    http://en.wikipedia.org/wiki/Disjoint_union
>
> is more explicit because it pairs the tag with the value:
>
>    (x,i)
>
> where x is the value and i is the tag.
>
> One reason for an explicit tag is that the bounded types may contain
> the same type twice.  This has lead to problems in boost::variant as
> evidenced by the post:
>
>    http://article.gmane.org/gmane.comp.parsers.spirit.general/17118
>
> In addition, both variant and tuple have a common part, a metafunction
> mapping from a tag to a type; hence, this same common part could be used
> to implement both tuple and a tagged variant.
>
> A variant which actually contained a tag field I think would be more
> general in that it would allow duplicate types among the bounded types
> just as a tuple's bounded types can contain duplicate types.
>
> -regards,
> Larry
>

Yes, this is a big problem with the current std.variant implementation (among other problems such as no recursive variants....). The best std.variant can offer right now is the 'type' property to identify what's stored in it.

std.variant is, unfortunately, not very useful if you want the semantics of variants in ML-style languages.

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
November 05, 2012
On Sunday, 4 November 2012 at 22:33:46 UTC, Alex Rønne Petersen
wrote:
> On 05-11-2012 00:31, evansl wrote:
>>   http://dlang.org/phobos/std_variant.html
>>
>> says:
>>
>>  This module implements a discriminated union type (a.k.a. tagged union,
>> algebraic type).
>>
>> Yet, the wiki page:
>>
>>   http://en.wikipedia.org/wiki/Tagged_union
>>
>> says:
>>
>>   a tag field explicitly indicates which one is in use.
>>
>> and I don't see any indication of a tag field in the std_variant.html
>> page.  Another wiki reference:
>>
>>   http://en.wikipedia.org/wiki/Disjoint_union
>>
>> is more explicit because it pairs the tag with the value:
>>
>>   (x,i)
>>
>> where x is the value and i is the tag.
>>
>> One reason for an explicit tag is that the bounded types may contain
>> the same type twice.  This has lead to problems in boost::variant as
>> evidenced by the post:
>>
>>   http://article.gmane.org/gmane.comp.parsers.spirit.general/17118
>>
>> In addition, both variant and tuple have a common part, a metafunction
>> mapping from a tag to a type; hence, this same common part could be used
>> to implement both tuple and a tagged variant.
>>
>> A variant which actually contained a tag field I think would be more
>> general in that it would allow duplicate types among the bounded types
>> just as a tuple's bounded types can contain duplicate types.
>>
>> -regards,
>> Larry
>>
>
> Yes, this is a big problem with the current std.variant implementation (among other problems such as no recursive variants....). The best std.variant can offer right now is the 'type' property to identify what's stored in it.
>
> std.variant is, unfortunately, not very useful if you want the semantics of variants in ML-style languages.

I've been working on an update to std.variant whose formal
submission has been held up by a PhD thesis and some health
issues, although I'm currently (slowly) doing a code
review/cleanup of it in the hope of finally submitting it. ( Old
code: https://jshare.johnshopkins.edu/rjacque2/public_html/ )
Anyways, my implementation has an internal 'tag' as does the
current implementation, IIRC. However, as the tag is a
meaningless random number, instead .type is provide access to the
meaningful typeinfo object of that class. And .type provides most
(all?) of the functionality of an int id:

auto var = Variant(5);
if(var.type == typeid(int)) {
     // Do something...
} else if(var.type == typeid(string)) {
    // Do something else...
}

But I am missing something as I found that the linked post wasn't
clear what the exact issue was, only that there was an issue. If
someone would like to clarify the problem (or any other with
Variant) it would be appreciated.

November 05, 2012
Am Mon, 05 Nov 2012 07:33:47 +0100
schrieb "Robert Jacques" <sandford@jhu.edu>:

> On Sunday, 4 November 2012 at 22:33:46 UTC, Alex Rønne Petersen wrote:
> > On 05-11-2012 00:31, evansl wrote:
> >>   http://dlang.org/phobos/std_variant.html
> >>
> >> says:
> >>
> >>  This module implements a discriminated union type (a.k.a.
> >> tagged union,
> >> algebraic type).
> >>
> >> Yet, the wiki page:
> >>
> >>   http://en.wikipedia.org/wiki/Tagged_union
> >>
> >> says:
> >>
> >>   a tag field explicitly indicates which one is in use.
> >>
> >> and I don't see any indication of a tag field in the
> >> std_variant.html
> >> page.  Another wiki reference:
> >>
> >>   http://en.wikipedia.org/wiki/Disjoint_union
> >>
> >> is more explicit because it pairs the tag with the value:
> >>
> >>   (x,i)
> >>
> >> where x is the value and i is the tag.
> >>
> >> One reason for an explicit tag is that the bounded types may
> >> contain
> >> the same type twice.  This has lead to problems in
> >> boost::variant as
> >> evidenced by the post:
> >>
> >> 
> >> http://article.gmane.org/gmane.comp.parsers.spirit.general/17118
> >>
> >> In addition, both variant and tuple have a common part, a
> >> metafunction
> >> mapping from a tag to a type; hence, this same common part
> >> could be used
> >> to implement both tuple and a tagged variant.
> >>
> >> A variant which actually contained a tag field I think would
> >> be more
> >> general in that it would allow duplicate types among the
> >> bounded types
> >> just as a tuple's bounded types can contain duplicate types.
> >>
> >> -regards,
> >> Larry
> >>
> >
> > Yes, this is a big problem with the current std.variant implementation (among other problems such as no recursive variants....). The best std.variant can offer right now is the 'type' property to identify what's stored in it.
> >
> > std.variant is, unfortunately, not very useful if you want the semantics of variants in ML-style languages.
> 
> I've been working on an update to std.variant whose formal submission has been held up by a PhD thesis and some health issues, although I'm currently (slowly) doing a code review/cleanup of it in the hope of finally submitting it. ( Old code: https://jshare.johnshopkins.edu/rjacque2/public_html/ ) Anyways, my implementation has an internal 'tag' as does the current implementation, IIRC. However, as the tag is a meaningless random number, instead .type is provide access to the meaningful typeinfo object of that class. And .type provides most (all?) of the functionality of an int id:
> 
> auto var = Variant(5);
> if(var.type == typeid(int)) {
>       // Do something...
> } else if(var.type == typeid(string)) {
>      // Do something else...
> }
> 
> But I am missing something as I found that the linked post wasn't clear what the exact issue was, only that there was an issue. If someone would like to clarify the problem (or any other with Variant) it would be appreciated.
> 

A little off-topic, but IIRC the typeid stuff is only used to allow arbitrary types in Variant. This is a valid use case, but could we use a simple enum/integer tag for Algebraic? There was a discussion about Variant's performance some time ago and if you don't need to store arbitrary types you're currently better of writing a custom discriminated union than using Algebraic.

November 05, 2012
On 11/05/12 00:33, Robert Jacques wrote:
> On Sunday, 4 November 2012 at 22:33:46 UTC, Alex Rønne Petersen wrote:
>> On 05-11-2012 00:31, evansl wrote:
>>>   http://dlang.org/phobos/std_variant.html
>>>
>>> says:
>>>
>>>  This module implements a discriminated union type (a.k.a. tagged union,
>>> algebraic type).
>>>
>>> Yet, the wiki page:
>>>
>>>   http://en.wikipedia.org/wiki/Tagged_union
>>>
>>> says:
>>>
>>>   a tag field explicitly indicates which one is in use.
>>>
>>> and I don't see any indication of a tag field in the std_variant.html page.  Another wiki reference:
>>>
>>>   http://en.wikipedia.org/wiki/Disjoint_union
>>>
>>> is more explicit because it pairs the tag with the value:
>>>
>>>   (x,i)
>>>
>>> where x is the value and i is the tag.
>>>
>>> One reason for an explicit tag is that the bounded types may contain the same type twice.  This has lead to problems in boost::variant as evidenced by the post:
>>>
>>>   http://article.gmane.org/gmane.comp.parsers.spirit.general/17118
>>>
>>> In addition, both variant and tuple have a common part, a metafunction mapping from a tag to a type; hence, this same common part could be used to implement both tuple and a tagged variant.
>>>
>>> A variant which actually contained a tag field I think would be more general in that it would allow duplicate types among the bounded types just as a tuple's bounded types can contain duplicate types.
>>>
>>> -regards,
>>> Larry
>>>
>>
>> Yes, this is a big problem with the current std.variant implementation (among other problems such as no recursive variants....). The best std.variant can offer right now is the 'type' property to identify what's stored in it.
>>
>> std.variant is, unfortunately, not very useful if you want the semantics of variants in ML-style languages.
> 
> I've been working on an update to std.variant whose formal submission has been held up by a PhD thesis and some health issues, although I'm currently (slowly) doing a code review/cleanup of it in the hope of finally submitting it. ( Old code: https://jshare.johnshopkins.edu/rjacque2/public_html/ ) Anyways, my implementation has an internal 'tag' as does the current implementation, IIRC. However, as the tag is a meaningless random number, instead .type is provide access to the meaningful typeinfo object of that class. And .type provides most (all?) of the functionality of an int id:
> 
> auto var = Variant(5);
> if(var.type == typeid(int)) {
>      // Do something...
> } else if(var.type == typeid(string)) {
>     // Do something else...
> }

Robert, I see no bounded types in the above Variant. Looking back at:

  http://dlang.org/phobos/std_variant.html

I see now that std.Variant doesn't require the set of
types to be bounded.  It's only Algebraic:

  http://dlang.org/phobos/std_variant.html#Algebraic

that has a bounded set of types.  I should have read
closer.  I mistakenly thought std.variant served the
same purpose as Boost.variant, but now I see that
Boost.variant and std.Algebraic serve similar purposes
in that they require a set of bounded types, but that
Boost.any and std.variant are similar in that the types
are unbounded (IOW, any type can be stored in std.variant
or Boost.any).

Sorry for not carefully reading.  So my question then is why doesn't ALgebraic have a tag.  This would allow:

  Algebraic!(int,int)

> 
> But I am missing something as I found that the linked post wasn't clear what the exact issue was, only that there was an issue. If someone would like to clarify the problem (or any other with Variant) it would be appreciated.
> 

If std.Algebraic is like Boost.Variant, then duplicate
bounded types are not allowed and leads to the problem mentioned
in the post on the spirit mailing list which I linked to in my
OP.  OOPS,  now I see why reading that post was not clear enough.
Maybe this earlier post in same spirit thread would be clearer.

http://article.gmane.org/gmane.comp.parsers.spirit.general/17113

In particular, note the phrase:

  neither can you use variant<string,string,int>
  because variant can't take duplicate types.

This can lead to problems in the spirit parser because
the attributes of parsing:

    a | b

where:
  phrase a has an attribute of type A
  phrase b has an attribute of type B
is:

    variant<A,B>

as noted near the bottom of:


http://www.boost.org/doc/libs/1_51_0/libs/spirit/doc/html/spirit/abstracts/attributes/compound_attributes.html

and if A and B are the same, then there's a problem because Boost.variant can't handle duplicates.

Hope that's clearer.

-regards,
Larry

BTW, recently there was a review of
another Boost library that has some similarity to
Boost.any.  It's called type_erasure:


http://steven_watanabe.users.sourceforge.net/type_erasure/libs/type_erasure/doc/html/index.html

Since std.Variant is similar to Boost.any (as noted above),
and since Boost.any is, in some ways, like Boost.type_erasure,
and since you're working on a revised std.Variant,
you might be interested in looking at type_erasure.
November 05, 2012
On Monday, 5 November 2012 at 14:13:41 UTC, evansl wrote:
> On 11/05/12 00:33, Robert Jacques wrote:
>> On Sunday, 4 November 2012 at 22:33:46 UTC, Alex Rønne Petersen
>> wrote:
>>> On 05-11-2012 00:31, evansl wrote:

[snip]

> If std.Algebraic is like Boost.Variant, then duplicate
> bounded types are not allowed and leads to the problem mentioned
> in the post on the spirit mailing list which I linked to in my
> OP.  OOPS,  now I see why reading that post was not clear enough.
> Maybe this earlier post in same spirit thread would be clearer.
>
> http://article.gmane.org/gmane.comp.parsers.spirit.general/17113
>
> In particular, note the phrase:
>
>   neither can you use variant<string,string,int>
>   because variant can't take duplicate types.
>
> This can lead to problems in the spirit parser because
> the attributes of parsing:
>
>     a | b
>
> where:
>   phrase a has an attribute of type A
>   phrase b has an attribute of type B
> is:
>
>     variant<A,B>
>
> as noted near the bottom of:
>
>
> http://www.boost.org/doc/libs/1_51_0/libs/spirit/doc/html/spirit/abstracts/attributes/compound_attributes.html
>
> and if A and B are the same, then there's a problem because
> Boost.variant can't handle duplicates.
>
> Hope that's clearer.
>
> -regards,
> Larry

Thank you for the clarification. Implementing an id seems reasonable feature request for algebraic. I've added a bugzilla request for it: http://d.puremagic.com/issues/show_bug.cgi?id=8962 Please have a look in case I missed anything.

> BTW, recently there was a review of
> another Boost library that has some similarity to
> Boost.any.  It's called type_erasure:
>
>
> http://steven_watanabe.users.sourceforge.net/type_erasure/libs/type_erasure/doc/html/index.html
>
> Since std.Variant is similar to Boost.any (as noted above),
> and since Boost.any is, in some ways, like Boost.type_erasure,
> and since you're working on a revised std.Variant,
> you might be interested in looking at type_erasure.

Thanks, I'll take a look at it.
November 05, 2012
On 11/05/12 13:53, Robert Jacques wrote:
> On Monday, 5 November 2012 at 14:13:41 UTC, evansl wrote:
>> On 11/05/12 00:33, Robert Jacques wrote:
>>> On Sunday, 4 November 2012 at 22:33:46 UTC, Alex Rønne Petersen wrote:
>>>> On 05-11-2012 00:31, evansl wrote:
> 
> [snip]
> 
>> If std.Algebraic is like Boost.Variant, then duplicate
>> bounded types are not allowed and leads to the problem mentioned
>> in the post on the spirit mailing list which I linked to in my
>> OP.  OOPS,  now I see why reading that post was not clear enough.
>> Maybe this earlier post in same spirit thread would be clearer.
>>
>> http://article.gmane.org/gmane.comp.parsers.spirit.general/17113
>>
>> In particular, note the phrase:
>>
>>   neither can you use variant<string,string,int>
>>   because variant can't take duplicate types.
>>
>> This can lead to problems in the spirit parser because
>> the attributes of parsing:
>>
>>     a | b
>>
>> where:
>>   phrase a has an attribute of type A
>>   phrase b has an attribute of type B
>> is:
>>
>>     variant<A,B>
>>
>> as noted near the bottom of:
>>
>>
>> http://www.boost.org/doc/libs/1_51_0/libs/spirit/doc/html/spirit/abstracts/attributes/compound_attributes.html
>>
>>
>> and if A and B are the same, then there's a problem because Boost.variant can't handle duplicates.
>>
>> Hope that's clearer.
>>
>> -regards,
>> Larry
> 
> Thank you for the clarification. Implementing an id seems reasonable feature request for algebraic. I've added a bugzilla request for it: http://d.puremagic.com/issues/show_bug.cgi?id=8962 Please have a look in case I missed anything.

The bugzilla request looks good to me, especially the way that the tuple and algebraic are made as similar as possible.  As I mentioned before, the thing that's similar is the metafunction mapping from tags to types.  Maybe that could be a future enhancement.

BTW, the idea of this metafunction map I first found in NuPrl, where these types of functions are called type-valued functions, expressed as:

  B:(A -> U_1)

where U_1 represents all the types, primitive and user defined, in c++, and A is something like an enum or unsigned or some other type serving as the set of possible tag values.

The above B expression is found here:

http://www.nuprl.org/book/Introduction_Type_Theory.html#SECTION00321000000000000000


where it's used to define:

  dependent functions (corresponding to std.tuple)
  dependent products  (corresponding to std.Algebraic)

Thought you might find that interesting, as I did.
> 
>> BTW, recently there was a review of
>> another Boost library that has some similarity to
>> Boost.any.  It's called type_erasure:
>>
>>
>> http://steven_watanabe.users.sourceforge.net/type_erasure/libs/type_erasure/doc/html/index.html
>>
>>
>> Since std.Variant is similar to Boost.any (as noted above),
>> and since Boost.any is, in some ways, like Boost.type_erasure,
>> and since you're working on a revised std.Variant,
>> you might be interested in looking at type_erasure.
> 
> Thanks, I'll take a look at it.

IIRC, the main difference between Boost.any and Boost.type_erasure is
type_erasure can be used to put some constraints on the contained type
such as requiring the type to support certain functions.
I think type_erasure calls the constraints concepts.  You can search for
"type_erasure" here:

  http://thread.gmane.org/gmane.comp.lib.boost.devel

to access some interesting discussions.

HTH.
-regards,
Larry




-regards,

November 05, 2012
On Sunday, 4 November 2012 at 22:31:56 UTC, evansl wrote:
> Yet, the wiki page:
>   http://en.wikipedia.org/wiki/Tagged_union
> says:
>   a tag field explicitly indicates which one is in use.
>
> and I don't see any indication of a tag field in the std_variant.html

 I remember a while back asking about the variant. I wanted to be able to specify an area in memory and say 'this is xxx', but couldn't; This was to help avoid having to manually make and manage something like 60 structs and far more complex code to manage that.

 This leads me to develop my own version (for built-in types); My version isn't anywhere complete (or clean enough) for publication, but enough for my own project (as read-only use).


 Hmmm curiously enough, i might be able to convert/rebuild by using a polymorphic struct that I'm tinkering with, but that seems like a lot of extra work.