July 03, 2019
On Wednesday, 3 July 2019 at 14:06:16 UTC, Jesse Phillips wrote:
> On Wednesday, 3 July 2019 at 14:01:17 UTC, Jesse Phillips wrote:
>> On Wednesday, 3 July 2019 at 13:34:38 UTC, Bert wrote:
>>> Interfaces are required because D does not support MI of classes. You will not be able to substitute one model for the other without inheritance. It's required.
>>
>> All I did was remove the interfaces:
>>
>> https://run.dlang.io/gist/3b14d69aa323d83e2736a0e2e0dece3f
>
> Now I remove your unneeded overrides:
>
> https://run.dlang.io/gist/28168b9e1265ab05da310c527079f6ac

404: Not Found


The problem with removing the interfaces is that when you try to extend the model by adding new classes you will then have multiple inheritance of classes and be screwed. You may be able to remove them in the simple example I gave but in general it will be impossible to make it work. One of the main reasons for interfaces is precisely to allow MI in a single inheritance language. The interfaces are the only way to avoid such future problems. In essence you are creating an anti-pattern.
July 04, 2019
On Wednesday, 3 July 2019 at 19:31:49 UTC, Bert wrote:
>
> The problem with removing the interfaces is that when you try to extend the model by adding new classes you will then have multiple inheritance of classes and be screwed. You may be able to remove them in the simple example I gave but in general it will be impossible to make it work. One of the main reasons for interfaces is precisely to allow MI in a single inheritance language. The interfaces are the only way to avoid such future problems. In essence you are creating an anti-pattern.

Huh, not sure what is up with that:
https://gist.github.com/run-dlang/bfc043093066da04f0d2bec5a07de459

I understand the purpose for interfaces, what I'm trying to understand is your requirements for this 'model' idea.

Your code made overzealous use of inheritance which I expect created some of your frustration. When I stated I did not see multiple inheritance in your code, you pursued it was and the interfaces were required. I have shown this is not true, so I ask you to consider what your needs actually are. I'm not creating any patterns I'm informing you of how the language works and meets your demonstrated need.
July 05, 2019
On Thursday, 4 July 2019 at 04:33:12 UTC, Jesse Phillips wrote:
> On Wednesday, 3 July 2019 at 19:31:49 UTC, Bert wrote:
>>
>> The problem with removing the interfaces is that when you try to extend the model by adding new classes you will then have multiple inheritance of classes and be screwed. You may be able to remove them in the simple example I gave but in general it will be impossible to make it work. One of the main reasons for interfaces is precisely to allow MI in a single inheritance language. The interfaces are the only way to avoid such future problems. In essence you are creating an anti-pattern.
>
> Huh, not sure what is up with that:
> https://gist.github.com/run-dlang/bfc043093066da04f0d2bec5a07de459
>

That works.

> I understand the purpose for interfaces, what I'm trying to understand is your requirements for this 'model' idea.
>
> Your code made overzealous use of inheritance which I expect created some of your frustration. When I stated I did not see multiple inheritance in your code, you pursued it was and the interfaces were required. I have shown this is not true, so I ask you to consider what your needs actually are. I'm not creating any patterns I'm informing you of how the language works and meets your demonstrated need.


You seem to think the example is a real world model and that all other models would work the same.

Let me ask you, do you think interfaces are never needed in oop? If they are, why? Do you realize that the modeling is just oop?

Now, I will explain why you are wrong, misunderstanding the problem, and how you changed the entire meaning of the program to cram it in to your misunderstanding.

1.

struct ModelB
{	
    class Animal : ModelA.Animal
    {

    }

    class Cat : ModelA.Cat
    {
		override Food LikesWhichFood() { writeln("Food D Type: ", fullyQualifiedName!Food); return new Cabbage; }					
		this() { }
		this(string n) { name = n; }
		
    }

	class Dog : ModelA.Dog
    {
		override Food LikesWhichFood() { writeln("Food D Type: ", fullyQualifiedName!Food); return new Donuts; }					
		this() { }
		this(string n) { name = n; }
    }

You've removed all the interfaces so you would not have MI. You believe that was as smart thing. But you have completely disconnected  ModelB from itself.

Now ModelB.Dog does not inheret from ModelB.Animal.

What happens if you extend ModelB.Animal? How is ModelB.Dog going to see that? It can't, it's not connected. You have not created a new model.  You have simply extended every class in ModelA. You have done nothing model wise.

2.

My original code:

	ModelA.iAnimal animal1 = new ModelB.Cat("Super Mittens");
	ModelA.iAnimal animal2 = new ModelB.Dog("Super Sparky");

you changed the returns to auto.

In mine, I'm using oop and animal1 is of class type ModelA but of instance type ModelB. By using auto you still have ModelB's(even though they are not longer really a Model). This may seem like no problem in this simple case but realize in a real problem ModelA be creating new objects using a factory. You won't have access to changing everything so easily. The whole point I did not use auto was to express this. I wanted to show how how animal1 as a ModelA could hold a ModelB and act properly.(i.e., inheritance).

If one has a class hierarchy, this is what you have done:

   A
 /   \
B     C

and you you have

   A  ---->  a
  /    \
B -> b   C -> c

Every class is just has a new derived base class for you to insert. This is just basic oop. This is not on a higher level. c is not related to a as C is to A.

What I have is this

  A  ---------->  a
/   \           /   \
B   C          b    c
-------------->
    --------------->


compared to yours:

  A  ---------->  a
/   \
B   C          b    c
-------------->
    --------------->


(notice that a, b, and c are not related directly in the fashion of the structure).

3. You have to realize you are wrong, that is the first step to understanding. I've tried to point it out but you are probably still thinking "But I'm right and he's wrong".

What you are doing is not modeling. That is the first realization. You have done nothing outside basic oop that everyone does. It's just class inheritence. You have some class X and you want a new one so you derive from it. You have a class Y and you want some new Y and you derive from it... but your does not explicitly connect X and Y in any way shape or form if they are connected.


What I'm doing is preserving the structure. When we derive a class, we preserve the base classes structure. This is called an embedding. The base class is embedded in the derived class and this allows the derived class to be the base class. That is, we can always substitute the derived in places where the base class is because the derived is the base class in *structure*.

But the same logic holds for relations between classes(which are models, frameworks, designs, etc). I'm trying to preserve the structure of the classes AND the structure between the classes. Do you see this?

https://en.wikipedia.org/wiki/Natural_transformation


The only thing I can say is that with what you are doing, you cannot subsistent one model for the other because you actually only have one model.

In my original code I have two models. The second model is fully derived from the first. It contains the entire structure of the first. It is true inheritance of models and it is oop.

It means that if a program was written with ModelA in mind, I can derive a new model called ModelB and drop it in place of it. I can extend my model and inside the model everything is in terms of ModelB(not mixing modelA stuff).


Look at this, the lines are inheritance:

  A  ---------->  a
/   \           /   \
B   C          b    c
-------------->
    --------------->


compared to yours:

  A  ---------->  a
/   \
B   C          b    c
-------------->
    --------------->


In yours, if I create a class b, it contains B and then A, but no a.
In mine, b contains B, A, AND a.

Yours you cannot get a. How will you get it's members? As far as your model is concerned, a is not connected to b. In mine a is directly connected to be(it inherits it). And the relationships B : A is preserved b : a.

You can see this in the code by trying to add a new method to ModelB.Animal... it does not show up in ModelB.Dog... ModelB.Animal is not related to ModelB.Dog. Hence you are not preserving the structure in ModelB that exists in ModelA.

This means if someone comes along and decides to model ModelB, they will be screwed because it no longer models A. You have broken "model inheritance".

Class inheritence doesn't break like this because it preserves the internal structure. Model inheritance doesn't break this because it preserves the internal structure... but D doesn't know about model inheritance so one can actually break it.


It's only going to be clear when you realize there is more to it than what you are thinking about. It may or may not be subtle.

It's purpose is a little more practical though. Your method will work but it requires hacks, factors, and all kinds of things to keep the modeling consistent and useful. You can cast objects and use factors to generate the appropriate types...

But in what I'm doing, one does not have too do all that.

ModelB knows about itself. ModelB.Dog knows about ModelB.Animal... not only ModelA.Animal.

Do you see the difference? I'm adding an arrow, it's not just an arrow, it's a structural relationship that has meaning(it is inheritance). I'm using *multiple inheritance* and you are using single inheritance. You can claim that I don't need multiple inheritance but really, you should be skeptical since obviously multiple inheritance will generally provide more(but never less).

You are throwing out a connection to fit the problem in to your own misconception.

If you want to see your problem, it's quite simple:


struct ModelB
{	
    class Animal : ModelA.Animal
    {
       void Fart();
    }

}

Your Dog is oblivious to Fart.. It can't see it, there is no arrow. Add it to your code...  You cannot do dog.Fart. You can cast, you can play games, but it is not naturally done like it should(like standard inheritance should work).

But if you do what I do, or had MI:

    class Dog : Animal, ModelA.Animal

Now Dog can see Fart. Now that is MI, can't be done in D, so we have to use interfaces.

Do you get it? The main thing to recognize is that you are pruning the structure... and so you have to absolutely make sure you are not cutting the tree down in the process, and unfortunately that is what you did in this case. You just need to recognize there is more too it to start seeing what it is. As long as you keep believing it can be simplified you will continue going down that dead end.



July 05, 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
July 06, 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.






July 06, 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.






July 07, 2019
On Friday, 5 July 2019 at 11:22:10 UTC, CheeseWiz wrote:

> You seem to think the example is a real world model and that all other models would work the same.

No I asked a question about your model and you said it couldn't be done without interfaces, I showed that wasn't the case.

>
> You've removed all the interfaces so you would not have MI. You believe that was as smart thing. But you have completely disconnected  ModelB from itself.
>
> Now ModelB.Dog does not inheret from ModelB.Animal.

Your model doesn't do that either, why? Because D doesn't have multiple inheritance. You would need `ModelB.Dog : ModelB.Animal, ModelA.Dog` but you can't because D does not allow for it.

> 2.
>
> My original code:
>
> 	ModelA.iAnimal animal1 = new ModelB.Cat("Super Mittens");
> 	ModelA.iAnimal animal2 = new ModelB.Dog("Super Sparky");
>
> you changed the returns to auto.

You are correct, and that only has the effect of forcing the cast I removed, my model matched the behavior of your model.


> 3. You have to realize you are wrong, that is the first step to understanding. I've tried to point it out but you are probably still thinking "But I'm right and he's wrong".

No, I don't think I am right, I think I was wrong because the model you provided was inaccurate for requirements you are placing on me.

A wise man once said to me, "You have to realize you are wrong, that is the first step to understanding"

See, what happened is you missed the point of removing all the interfaces, it was to show that the interfaces you chose to add were not necessary to meet the code you had put into place, it was also intended to show that your inheritance of all the different interfaces in all classes was excessive and causing issues.

Here is a more accurate representation of your model when correctly written in D.

https://gist.github.com/JesseKPhillips/b891604444f4aee72c705b498a206d50

What you will notice is that the ModelB.Animal class is commented out, the reason for this is because it is not utilized your original model as you never inherited that class, all you did was `alias Attack = Animal.Attack;` but that isn't doing what you think it is doing.

I instructed ModelB.iAnimal to `override iFood LikesWhichFood()` because I wanted covariance and have ModelB Animials to return ModelB.iFood.

So please continue to insult my understanding of how D inheritance works, I'd like to hear more about your unbounded knowledge.
July 07, 2019
On Sunday, 7 July 2019 at 16:37:32 UTC, Jesse Phillips wrote:
> On Friday, 5 July 2019 at 11:22:10 UTC, CheeseWiz wrote:
>
>> You seem to think the example is a real world model and that all other models would work the same.
>
> No I asked a question about your model and you said it couldn't be done without interfaces, I showed that wasn't the case.
>
>>
>> You've removed all the interfaces so you would not have MI. You believe that was as smart thing. But you have completely disconnected  ModelB from itself.
>>
>> Now ModelB.Dog does not inheret from ModelB.Animal.
>
> Your model doesn't do that either, why? Because D doesn't have multiple inheritance. You would need `ModelB.Dog : ModelB.Animal, ModelA.Dog` but you can't because D does not allow for it.
>
>> 2.
>>
>> My original code:
>>
>> 	ModelA.iAnimal animal1 = new ModelB.Cat("Super Mittens");
>> 	ModelA.iAnimal animal2 = new ModelB.Dog("Super Sparky");
>>
>> you changed the returns to auto.
>
> You are correct, and that only has the effect of forcing the cast I removed, my model matched the behavior of your model.
>
>
>> 3. You have to realize you are wrong, that is the first step to understanding. I've tried to point it out but you are probably still thinking "But I'm right and he's wrong".
>
> No, I don't think I am right, I think I was wrong because the model you provided was inaccurate for requirements you are placing on me.
>
> A wise man once said to me, "You have to realize you are wrong, that is the first step to understanding"
>
> See, what happened is you missed the point of removing all the interfaces, it was to show that the interfaces you chose to add were not necessary to meet the code you had put into place, it was also intended to show that your inheritance of all the different interfaces in all classes was excessive and causing issues.
>
> Here is a more accurate representation of your model when correctly written in D.
>
> https://gist.github.com/JesseKPhillips/b891604444f4aee72c705b498a206d50
>
> What you will notice is that the ModelB.Animal class is commented out, the reason for this is because it is not utilized your original model as you never inherited that class, all you did was `alias Attack = Animal.Attack;` but that isn't doing what you think it is doing.
>

The compiler forced me to do that to override the base class. Irregardless, it is irrelevant.

> I instructed ModelB.iAnimal to `override iFood LikesWhichFood()` because I wanted covariance and have ModelB Animials to return ModelB.iFood.
>
> So please continue to insult my understanding of how D inheritance works, I'd like to hear more about your unbounded knowledge.

I'm not insulting you. I was pointing out that your incessant "You don't needed interfaces" is wrong. I'm sorry you seem to think that when someone gives an example that example is all that matter. I have to give examples to express concepts.

I was trying to get you to realize that you are missing the point but you seem to want to keep on harping it. I will make it clear: THE EXAMPLE I GAVE IS AN ****EXAMPLE****. Is that clear?

Here is the definition of an example:

ex·am·ple
/iɡˈzampəl/
 Learn to pronounce
noun
1.
a thing characteristic of its kind or illustrating a general rule.
"it's a good example of how European action can produce results"
synonyms:	specimen, sample, exemplar, exemplification, instance, case, representative case, typical case, case in point, illustration
"a fine example of a 16th-century longhouse"
2.
a person or thing regarded in terms of their fitness to be imitated or the likelihood of their being imitated.
"it is vitally important that parents should set an example"
synonyms:	precedent, lead, guide, model, pattern, blueprint, template, paradigm, exemplar, ideal, standard; More
verb
1.
be illustrated or exemplified.


What you did was make my example as if it were an actual problem. It should have been clear that the example was ridiculous as a problem by it's nature.

The whole problem was about modeling, not about somehow optimizing the example.  You failed at that, I'm sorry, I tried to get you to understand that so we could move past it but you still want to seem to harp on it. I told you several times you were wrong in removing the interfaces. You took it as being wrong in making that example work, I was telling you that it is wrong to remove it because it destroys the examples as being an example of the larger problem I am talking about. I stated many times what I was trying to do and you insisted at every step I didn't need interfaces and I told you they were required for the general problem. You ignored that and now you want to blame me for you ignoring it. I told you many times you can't ignore it and you are wrong for doing so but now, again, it is my fault for you ignoring it. You still seem to think you are right because you reduced the example to an equivalent example that is functionally the same. Well, duh... but now what the fuck am I suppose to do with real problems that actually matter rather than some contrived and pathetic example that was meant to be precisely an example to illustrate the more general problem(the problem I did state in more general terms)?

I mean, seriously, what the hell is one suppose to do? Give an example and create in in such a way that no one could ever reduce it to a example that then is irrelevant? Come on! That is now how things work no matter how much you want them to!

See, what you were suppose to do in your brain is say "Ok, this is an example, I'll assume in requirements for inheritance are necessary in the larger scope and because he has told me several times they are... I'll just take his word for it". But no, it's all my fault for not just accepting your answer as being correct.





July 07, 2019
On Sunday, 7 July 2019 at 20:42:00 UTC, CheeseWiz wrote:
> On Sunday, 7 July 2019 at 16:37:32 UTC, Jesse Phillips wrote:
>> https://gist.github.com/JesseKPhillips/b891604444f4aee72c705b498a206d50
>>
>> What you will notice is that the ModelB.Animal class is commented out, the reason for this is because it is not utilized your original model as you never inherited that class, all you did was `alias Attack = Animal.Attack;` but that isn't doing what you think it is doing.
>>
>
> The compiler forced me to do that to override the base class. Irregardless, it is irrelevant.

It did not force you to do that because you did not inherit that base class.

You started with complaints about how verbose D was with the modeling pattern you wanted to express, you claimed it was possible and this was an example.

The example actually shows that D does not allow you to model as you desired, but that wasn't the claim you were making, you said the example did what you wanted but it doesn't.
July 07, 2019
On Saturday, 6 July 2019 at 19:45:24 UTC, CheeseWiz wrote:
> 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.

Can you please show in code something that can't be done with the code I wrote (or better, https://gist.github.com/Biotronic/f362732f83e7b4c6a4b3370919d73be3, which fixes some issues in the original)?

I know there are language limits that no library code can overcome, but for the vast majority of cases, this is no issue. I can get all of this to work:

unittest {
    // Implicit conversions to ModelA:
    ModelB.Dog a = new ModelB.Dog();
    ModelA.Dog b = a;
    ModelB.Animal c = a;
    ModelA.Animal d = c;

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

    // Methods are inherited from the corresponding class in the base model:
    assert(a.eat() == "foo.ModelA.Dog");
    assert(b.eat() == "foo.ModelA.Dog");
    assert(c.eat() == "foo.ModelA.Dog");
    assert(d.eat() == "foo.ModelA.Dog");

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

    // bite(), however, is not overridden, so ModelA's version is used:
    assert(a.bite() == "foo.ModelA.Dog");
    assert(b.bite() == "foo.ModelA.Dog");

    // Managed to fix casting from ModelA to ModelB:
    assert(cast(ModelB.Dog)d !is null);
}

I'm unsure what functionality 'proper' inheritance buys you over what I've made. (sugar, sure. But functionality?)

Since my code may be somewhat hard to follow, I'll describe what it does: mixin inherit!ModelA inside ModelB.Dog creates a new class derived from ModelA.Dog that points to the ModelB.Dog instance, and forwards method calls to this where appropriate. We then use alias this to make ModelB.Dog implicitly cast to this new class.

To use diagram somewhat like yours: https://i.imgur.com/t4z9c3D.png (black lines are regular inheritance, orange ones are regular inheritance using AutoImplement, and dashed lines are alias this)

So the classes defined in ModelB don't derive from anything in ModelA, but use language features to behave as if, in any way we care. If there are cases we care about that I haven't thought of, I'd love to be told of them.


> 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.

I believe this is very adequately covered in my code. If you have an actual counterexample, please show it.


> 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 fail to see how my code precludes this. Please to show?


> 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).

This is either perfectly obvious, or you are describing something very different from what it seems you are describing. If the latter, please try again, as I really want to understand.


> 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?

It does have the inheritance relationships, just not the way you may be expecting them.

--
  Simen
1 2
Next ›   Last »