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