D modeling

Simen Kjærås simen.kjaras at gmail.com
Fri Jul 5 12:24:06 UTC 2019


On Friday, 5 July 2019 at 11:22:10 UTC, CheeseWiz wrote:
> I'm trying to preserve the structure of the classes AND the 
> structure between the classes.

So what you want is for this code to work, right?

import std.stdio;

struct ModelA {
     class Animal {}
     class Dog : Animal {
         void bark() {
             writeln("ModelA barks!");
         }
         void bite() {
             writeln("ModelA bites!");
         }
     }
}

struct ModelB {
     class Animal {
         mixin inherit!ModelA;
     }
     class Dog : Animal {
         mixin inherit!ModelA;
         void bark() {
             writeln("ModelB Barks!");
         }
     }
}

unittest {
     ModelB.Dog a = new ModelB.Dog();
     ModelA.Dog b = a;
     ModelA.Animal c = b;
     ModelA.Animal d = a;

     assert(a !is null);
     assert(b !is null);
     assert(c !is null);
     assert(d !is null);

     // bark() is overridden in ModelB.Dog, so that's the version 
what's being called:
     a.bark(); // ModelB Barks!
     b.bark(); // ModelB Barks!

     // bite(), however, is not overridden, so ModelA's version is 
used:
     b.bite(); // ModelA bites!
     a.bite(); // ModelA bites!
}


As is hinted at by the `mixin inherit!ModelA;` lines above, 
mixins can sorta make this work. Here's a PoC that makes the 
above code work:

mixin template inherit(ParentModel) {
     static assert(is(typeof(this) == class), "inherit only works 
for classes");
     static assert(__traits(hasMember, ParentModel, 
typeof(this).stringof), "inherit works only for models matching 
the same class structure");

     alias ThisClass = typeof(this);
     alias ParentClass = __traits(getMember, ParentModel, 
typeof(this).stringof);

     import std.typecons : AutoImplement;
     static class Base : ParentClass {
         ThisClass zis;
     }
     template What(alias func) {
         enum funcName = __traits(identifier, func);
         static if (__traits(hasMember, ThisClass, funcName)) {
             enum What =  __traits(isVirtualFunction, func) &&
                          __traits(isVirtualFunction, 
__traits(getMember, ThisClass, __traits(identifier, func)));
         } else {
             enum What = false;
         }
     }
     template How(T, alias func) {
         import std.format : format;
         enum How = q{return zis.%1$s(args);}
             .format(__traits(identifier, func));
     }
     AutoImplement!(Base, How, What) _proxyParent;
     alias _proxyParent this;

     this() {
         _proxyParent = new typeof(_proxyParent)();
         _proxyParent.zis = this;
     }
}

Of course, it's ugly as all hell, and there are some issues (like 
casting from ModelA.Dog back to ModelB.Dog) that simply can't be 
handled by library code, but for limited applications, this works.

--
   Simen


More information about the Digitalmars-d mailing list