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 !

Reply via email to