Shameless autopromotion : type safe tagged union in D

Artur Skawina art.08.09 at gmail.com
Fri May 10 08:11:46 PDT 2013


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


More information about the Digitalmars-d-announce mailing list