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

Reply via email to