D modeling

CheeseWiz CheesyFritos3 at gmail.com
Sat Jul 6 02:49:30 UTC 2019


On Friday, 5 July 2019 at 12:24:06 UTC, Simen Kjærås wrote:
> 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

No, sorry, The classes have to actually inherit. The model itself 
has to be substitutable in all ways in to the original model, 
else it is not derived.

There is no way for ModelB to be a drop in replacement and so to 
preserve the structure. You should see my other long post about 
this.

Without inheritance(and MI but having to use interfaces) it will 
be impossible to make all this work and then the whole point 
would be useless.

There are two things:

1. Any new model must preserve all the structure of the old, else 
it won't work. inheritance does this, that is the whole point. If 
the structure is not preserved want can't substitute the derived 
class or model for the base class or model. If you leave out 
"connections" then something will go wrong at some point. It's 
like creating, say, a circuit from a schematic and leaving out 
wires saying "Oh, this wire doesn't matter" when, in fact, it 
does.  This is wiring up the modelB to modelA structurally. This 
could be called inter-model inheritance.

2. The model must be properly extendable within itself. By 
removing the intra-model inheritance(like Jesse did). This allows 
one to work within the model as if they were working completely 
from the original model, but as if it were entirely new(meaning 
one can add new structure but not remove structure).

I think the confusing part for you guys is that both types are 
still basic inheritance. Ya'll are not recognizing that there is 
a subtle distinction between the conceptually. Model 
inheritance(inter-model) is analogous to class 
inheritance(inter-model).

It's sort of like having an element operation and then extending 
it too work on arrays. The same underlying operation is used but 
there is a subtle difference in that one has to iterate over the 
arrays and apply the operation. The element operation is class 
inheritance and the array "operation" is model inheritance. It's 
a little more complex than and hence the "subtle details".

You guys are removing the very code that allows one to create a 
truly *derived* *model*. It's not derived unless it's 
derived(meaning all the structure is preserved). This applies to 
classes as well... but since D and oop already handle all the 
details for classes it is not an issue and no one thinks about 
it. Since D does not handle models or have such concepts and they 
are not commonly thought of in such "forest views" one has to be 
more careful.


It's simple as this:

Definition: Model - A model is a collection of classes and their 
inheritance relationships. Hence it is a category or a a directed 
graph or an inheritance hierarchy.

Ok?

Definition: Model Inheritance - A preservation of a model's 
structure[called the base model] inside a new model, called the 
derived model.


Note that these parallel classes. Classes contain members and one 
can think of it as a very simple graph. Models contain classes 
and one can think of it as a very simple graph but at a higher 
level. Each node in the graph is a class and hence it has a 
subgraph.

But just like you can't partially inherent a class and you can't 
partially inherit a model. In D, you can do it only because D 
doesn't understand models... but if you do it wrong you will run 
in to major problems. It would be akin too trying to implement 
classes in a language by hand and forgetting to include some 
members, but not having the compiler able to check for you.

This is not complex or a "hard problem". It's very simple. Try 
not to over complicate it. The definitions above, if understood 
correctly, should be enough.

Thanks for wasting your time on it though ;) Sorry you 
misunderstanding it ;/ Maybe your code can be adapted though, at 
the very least you'll have to add the inheritance relationships, 
maybe that will fix it and make it all work right?

I will say that in the code I posted, you cannot remove the 
interfaces nor the inheritance relationships. Doing that 
completely destroys everything. If you think it can you are not 
understanding the problem correctly and should focus on realizing 
why it is necessary.

Try to think of it in terms of a real world application. Say a 
program that uses a model, such as a video game that uses oop to 
manage the video game objects... and then you create an entirely 
new model that adds something new to the model. Rather than 
extend each class individually you want extend the entire model 
to a new one in a consistent and logical way.

You do this by copying and pasting all the "structure". But your 
model won't be able to just drop in and replace the original 
because it doesn't inherit in any way... so you start adding 
inheritance, but now it's MI because your model already has 
inheritance in it(since the original model had it since it was 
oop based). Now you have to use interfaces because of SI in D. If 
you do everything right, and the original model was designed with 
proper object construction that allows extension(e.g., overriding 
"new" or having a factory) then  your new model will can simply 
be dropped in to the original model without issue. EXACTLY the 
same as how it would work for a single class and object. [that is 
the goal at least and to make that happen requires some work, but 
one is properly extending models the other is proper object 
creation]

If done right though, and ideally with help from the compiler, it 
becomes very simple too do so. You can think fo class inheritance 
as a very slimmed down and naive version of model inheritance. 
class inheritance is model inheritance because a simple base 
class - derived class is a model.

You can think of traditional inheritance as being a dumbed down 
version of model inheritance or model inheritance is a 
generalization of class inheritance.








More information about the Digitalmars-d mailing list