www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Shameless autopromotion : type safe tagged union in D

reply "deadalnix" <deadalnix gmail.com> writes:
http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/

A trick that I used to use more and more, so I ended up creating 
a generic solution and wrote an article about it.
May 10 2013
next sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 10 May 2013 at 12:32:50 UTC, deadalnix wrote:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/

 A trick that I used to use more and more, so I ended up 
 creating a generic solution and wrote an article about it.
Fancy some proof-reading again?
May 10 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 10 May 2013 at 12:47:17 UTC, John Colvin wrote:
 On Friday, 10 May 2013 at 12:32:50 UTC, deadalnix wrote:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/

 A trick that I used to use more and more, so I ended up 
 creating a generic solution and wrote an article about it.
Fancy some proof-reading again?
I went ahead and did a brief pass over it as I read it: http://db.tt/DqRbEO5u Nice article. This is the sort of thing that D really excels at compared to C++. Is this on Reddit yet?
May 10 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Friday, 10 May 2013 at 13:04:58 UTC, John Colvin wrote:
 On Friday, 10 May 2013 at 12:47:17 UTC, John Colvin wrote:
 On Friday, 10 May 2013 at 12:32:50 UTC, deadalnix wrote:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/

 A trick that I used to use more and more, so I ended up 
 creating a generic solution and wrote an article about it.
Fancy some proof-reading again?
I went ahead and did a brief pass over it as I read it: http://db.tt/DqRbEO5u
Awesome, I'll update the article.
 Nice article. This is the sort of thing that D really excels at 
 compared to C++.

 Is this on Reddit yet?
No, feel free to put it if you think it is appropriate !
May 10 2013
next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Friday, 10 May 2013 at 13:51:11 UTC, deadalnix wrote:
 Is this on Reddit yet?
No, feel free to put it if you think it is appropriate !
http://www.reddit.com/r/programming/comments/1e2h99/type_safe_tagged_union_in_d/ Someone else did.
May 10 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/10/13 10:15 AM, deadalnix wrote:
 On Friday, 10 May 2013 at 13:51:11 UTC, deadalnix wrote:
 Is this on Reddit yet?
No, feel free to put it if you think it is appropriate !
http://www.reddit.com/r/programming/comments/1e2h99/type_safe_tagged_union_in_d/ Someone else did.
I think this link went to spam. Posted here: http://www.reddit.com/r/programming/comments/1e2x6a/typesafe_tagged_unions_in_the_d_programming/ Andrei
May 10 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/10/13 1:49 PM, Andrei Alexandrescu wrote:
 On 5/10/13 10:15 AM, deadalnix wrote:
 On Friday, 10 May 2013 at 13:51:11 UTC, deadalnix wrote:
 Is this on Reddit yet?
No, feel free to put it if you think it is appropriate !
http://www.reddit.com/r/programming/comments/1e2h99/type_safe_tagged_union_in_d/ Someone else did.
I think this link went to spam. Posted here: http://www.reddit.com/r/programming/comments/1e2x6a/typesafe_tagged_unions_in_the_d_programming/
A general note about posting to reddit: it often happens that posts from infrequent posters go to spam by means of some automatic rule. When that happens you need to message the moderators and politely ask them to manually instate the post because it's legit. Once you accumulate karma and all, your posts will be auto-approved. I've done that for a while and accumulated good karma (and a good relationship with the mods to the extent that could be called such). So if you don't care about accumulating reddit points feel free to ask me to post links on your behalf. But of course the more strong posters in the D community, the better. Andrei
May 10 2013
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 5/10/2013 10:56 AM, Andrei Alexandrescu wrote:
 A general note about posting to reddit: it often happens that posts from
 infrequent posters go to spam by means of some automatic rule. When that
happens
 you need to message the moderators and politely ask them to manually instate
the
 post because it's legit. Once you accumulate karma and all, your posts will be
 auto-approved.

 I've done that for a while and accumulated good karma (and a good relationship
 with the mods to the extent that could be called such). So if you don't care
 about accumulating reddit points feel free to ask me to post links on your
 behalf. But of course the more strong posters in the D community, the better.
The post will also get a lot more upvotes if an abstract is also posted as the first comment on reddit. Otherwise, people won't click on the link.
May 10 2013
prev sibling parent reply "Jesse Phillips" <Jessekphillips+D gmail.com> writes:
On Friday, 10 May 2013 at 17:56:14 UTC, Andrei Alexandrescu wrote:
 A general note about posting to reddit: it often happens that 
 posts from infrequent posters go to spam by means of some 
 automatic rule. When that happens you need to message the 
 moderators and politely ask them to manually instate the post 
 because it's legit. Once you accumulate karma and all, your 
 posts will be auto-approved.
Well that is stupid. It would be like StackOverflow closing questions of new users and waiting for people to vote to open.
May 10 2013
parent "SomeDude" <lovelydear mailmetrash.com> writes:
On Friday, 10 May 2013 at 19:23:45 UTC, Jesse Phillips wrote:
 On Friday, 10 May 2013 at 17:56:14 UTC, Andrei Alexandrescu 
 wrote:
 A general note about posting to reddit: it often happens that 
 posts from infrequent posters go to spam by means of some 
 automatic rule. When that happens you need to message the 
 moderators and politely ask them to manually instate the post 
 because it's legit. Once you accumulate karma and all, your 
 posts will be auto-approved.
Well that is stupid. It would be like StackOverflow closing questions of new users and waiting for people to vote to open.
My submissions now all go to the spam section even though I have more than 1300 karma of comment and 800 karma of submission. It's fucking annoying.
May 12 2013
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 10 May 2013 at 13:51:11 UTC, deadalnix wrote:
 Awesome, I'll update the article.
Andrei pointed out that the title needed fixing: I suggest: Type-safe tagged unions in the D programming language. Type-safe tagged unions in D.
May 10 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 10 May 2013 at 14:53:23 UTC, John Colvin wrote:
 On Friday, 10 May 2013 at 13:51:11 UTC, deadalnix wrote:
 Awesome, I'll update the article.
Andrei pointed out that the title needed fixing: I suggest: Type-safe tagged unions in the D programming language. Type-safe tagged unions in D.
I updated everything. Now I need to sleep :D Thank you very much my english if often very ad hoc.
May 10 2013
prev sibling next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
10-May-2013 16:32, deadalnix пишет:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/


 A trick that I used to use more and more, so I ended up creating a
 generic solution and wrote an article about it.
Neat but somewhat limited. E.g. this is exactly the same switch madness we sought to avoid: void process(T)(T data) { alias Type = typeof(data); static if(is(Type == A)) { // Code that handle the case where it is an A. } else static if(is(Type == B)) { // Code that handle the case where it is an B. } else { static assert(0, "You must handle type " ~ Type.stringof); } } t.apply!process(); I'd rather see another idiom supported too: t.apply!(processA, processB)(); where e.g. void proccessA(A value){ ... } void processB(B value){ ... } Anther thing is that will allow succinct notations like: int squared = t.apply!( (A a) => a.x*a.x + a.y*a.y, (B b) => b.x*b.x + b.y*b.y + b.z*b.z )(); I sure don't fancy putting static if into lambdas. Another thing about it is it allows specifying safe catch all or default case. -- Dmitry Olshansky
May 10 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 10 May 2013 at 13:11:37 UTC, Dmitry Olshansky wrote:
 E.g. this is exactly the same switch madness we sought to avoid:
The article don't plan to avoid this, but to make the tagged union safe. I agree this is a plus, but didn't really took time to make that work.
 void process(T)(T data) {
     alias Type = typeof(data);

     static if(is(Type == A)) {
         // Code that handle the case where it is an A.
     } else static if(is(Type == B)) {
         // Code that handle the case where it is an B.
     } else {
         static assert(0, "You must handle type " ~ 
 Type.stringof);
     }
 }

 t.apply!process();


 I'd rather see another idiom supported too:

 t.apply!(processA, processB)();

 where e.g.
 void proccessA(A value){ ... }

 void processB(B value){ ... }
That can work indeed.
 Anther thing is that will allow succinct notations like:

 int squared = t.apply!(
 	(A a) => a.x*a.x + a.y*a.y,
 	(B b) => b.x*b.x + b.y*b.y + b.z*b.z
 )();

 I sure don't fancy putting static if into lambdas.
 Another thing about it is it allows specifying safe catch all 
 or default case.
That last one won't work. DMD don't accept locals here, even if they are functions.
May 10 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/10/13 8:32 AM, deadalnix wrote:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/


 A trick that I used to use more and more, so I ended up creating a
 generic solution and wrote an article about it.
Article is good, could use a few copyediting fixes (including in title). Any volunteers? Andrei
May 10 2013
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 10 May 2013 at 14:37:49 UTC, Andrei Alexandrescu wrote:
 On 5/10/13 8:32 AM, deadalnix wrote:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/


 A trick that I used to use more and more, so I ended up 
 creating a
 generic solution and wrote an article about it.
Article is good, could use a few copyediting fixes (including in title). Any volunteers? Andrei
Done (except the title) http://forum.dlang.org/post/dszacipmkljzjybcojzm forum.dlang.org
May 10 2013
prev sibling next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 05/10/13 14:32, deadalnix wrote:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/
 
 A trick that I used to use more and more, so I ended up creating a generic
solution and wrote an article about it.
Nothing 'shameless' about it. But Real Programmers don't use mixins... struct TU(TYPES...) { union { TYPES data; } ubyte type; static assert(TYPES.length<=typeof(type).max); T opAssign(T)(T a) { foreach(N, TYPE; TYPES) static if (is(T==TYPE)) { type = N; return data[N] = a; } assert(0); } this(T)(T a) { this = a; } DT as(DT)() property { foreach(N, TYPE; TYPES) static if (is(DT==TYPE)) { if (type==N) return data[N]; else assert(0, "Cannot access a '"~typeString(type)~"' as "~DT.stringof); } assert(0); } auto ref apply(alias f)() { foreach(N, TYPE; TYPES) static if (is(typeof(f(data[N])))) // Comment this line out for strict CT checks. if (N==type) return f(data[N]); assert(0, "Could not apply '"~typeof(f).stringof~"' to "~typeString(type)); } static string typeString()(typeof(type) n) { foreach(N, TYPE; TYPES) if (N==n) return TYPE.stringof; assert(0); } } double sqr(double a) { return a*a; } int sqr(int a) { return a*a; } void main() { import std.stdio; TU!(int, double, string) u; u = 257; writeln(u); writeln(u.data[0], ", ", u.data[1]); writeln(u.as!int); //writeln(u.as!double); // RT error writeln(u.apply!sqr()); u = 3.14; writeln(u.apply!sqr()); u = "blah"; //writeln(u.apply!sqr()); // CT error in 'strict' mode, RT error otherwise. // Not currently accepted: //writeln(u.apply!(function(a){return a*a;})()); //writeln(u.apply!(a=>a*a)()); } Something that wasn't obvious from your examples is that templates are not necessary when implementing the 'processing' functions - overloading is enough. The interesting aspect of this is what improvements to the language would help to make this code both a) simpler and more readable, and b) even more efficient. Manual optimizations, such as 'if-sequnences'->'switch', should /not/ result in harder to read code. The locals-can't-be-parms-to-local-templates restriction should only apply when really necessary (for example: static functions/lambdas can be allowed). Etc. artur
May 10 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 10 May 2013 at 15:12:01 UTC, Artur Skawina wrote:
 On 05/10/13 14:32, deadalnix wrote:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/
 
 A trick that I used to use more and more, so I ended up 
 creating a generic solution and wrote an article about it.
Nothing 'shameless' about it. But Real Programmers don't use mixins... struct TU(TYPES...) { union { TYPES data; } ubyte type; static assert(TYPES.length<=typeof(type).max); T opAssign(T)(T a) { foreach(N, TYPE; TYPES) static if (is(T==TYPE)) { type = N; return data[N] = a; } assert(0); } this(T)(T a) { this = a; } DT as(DT)() property { foreach(N, TYPE; TYPES) static if (is(DT==TYPE)) { if (type==N) return data[N]; else assert(0, "Cannot access a '"~typeString(type)~"' as "~DT.stringof); } assert(0); } auto ref apply(alias f)() { foreach(N, TYPE; TYPES) static if (is(typeof(f(data[N])))) // Comment this line out for strict CT checks. if (N==type) return f(data[N]); assert(0, "Could not apply '"~typeof(f).stringof~"' to "~typeString(type)); } static string typeString()(typeof(type) n) { foreach(N, TYPE; TYPES) if (N==n) return TYPE.stringof; assert(0); } } double sqr(double a) { return a*a; } int sqr(int a) { return a*a; } void main() { import std.stdio; TU!(int, double, string) u; u = 257; writeln(u); writeln(u.data[0], ", ", u.data[1]); writeln(u.as!int); //writeln(u.as!double); // RT error writeln(u.apply!sqr()); u = 3.14; writeln(u.apply!sqr()); u = "blah"; //writeln(u.apply!sqr()); // CT error in 'strict' mode, RT error otherwise. // Not currently accepted: //writeln(u.apply!(function(a){return a*a;})()); //writeln(u.apply!(a=>a*a)()); } Something that wasn't obvious from your examples is that templates are not necessary when implementing the 'processing' functions - overloading is enough. The interesting aspect of this is what improvements to the language would help to make this code both a) simpler and more readable, and b) even more efficient. Manual optimizations, such as 'if-sequnences'->'switch', should /not/ result in harder to read code. The locals-can't-be-parms-to-local-templates restriction should only apply when really necessary (for example: static functions/lambdas can be allowed). Etc. artur
Nice improvement, especially the opAssign. To be 100% fait, I didn't implemented it as I didn't needed it, but destruction is also something that can go wrong. I sure like the absence of mixins !
May 10 2013
prev sibling next sibling parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
W dniu 10.05.2013 14:32, deadalnix pisze:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/


 A trick that I used to use more and more, so I ended up creating a
 generic solution and wrote an article about it.
Here's my try on this: https://github.com/pszturmaj/json-streaming-parser/blob/master/json.d#L111 lines 111-184. It supports Self notation, so it's possible to create recursive unions given that Self is accessible through some indirection. TypeTag should be an enum with increasing values starting with 0. I just noticed, opAssign is prepended with underscore, I probably forgot to remove it after debugging:)
May 10 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 05/10/2013 02:32 PM, deadalnix wrote:
 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/


 A trick that I used to use more and more, so I ended up creating a
 generic solution and wrote an article about it.
I'd have implemented your TaggedUnion struct as follows. (I believe this is equivalent to your implementation.) struct TaggedUnion(T...){ private{ union{ T members; } int tag; static int indexOf(S)(){ foreach(i,t;T) static if(is(S==t)) return i; return -1; } } this(T)(T t) if(~indexOf!T){ members[indexOf!T]=t; tag=indexOf!T; } auto ref apply(alias fun)(){ switch(tag){ foreach(i,_;T) case i: return fun(members[i]); default: assert(0); } } } But note that this is as unsafe as the original implementation. You will at least have to provide a postblit constructor and a destructor in order to keep the promise of safety.
May 10 2013
prev sibling parent reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Fri, 10 May 2013 14:32:48 +0200
"deadalnix" <deadalnix gmail.com> wrote:

 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/
 
 A trick that I used to use more and more, so I ended up creating 
 a generic solution and wrote an article about it.
Nice article, but is there any particular problem with std.variant.Algebraic?
May 16 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 16 May 2013 at 18:30:22 UTC, Nick Sabalausky wrote:
 On Fri, 10 May 2013 14:32:48 +0200
 "deadalnix" <deadalnix gmail.com> wrote:

 http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/
 
 A trick that I used to use more and more, so I ended up 
 creating a generic solution and wrote an article about it.
Nice article, but is there any particular problem with std.variant.Algebraic?
Yes, : it is user responsibility to poll types and act accordingly. In the presented code, this is the responsibility of the data structure. For instance, if I add a new type, with Algebraic, I'll have to go over all my code base to patch every use. If I don't, my code become silently incorrect. With the presented solution, I'll get a compile time error.
May 16 2013