www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D modeling

reply CheeseWiz <CheesyFritos gmail.com> writes:
Here is the code, It would be nice if D could do proper modeling 
of models. One can understand the issues as described in the 
comments in the main. The idea is simple, we have a model(a set 
of interrelated classes that are used for some purpose(which can 
be called a model or a framework)) and we want to derive an new 
model from it(using inheritance of models, it's similar to 
inheritance of classes but is based on the set and internal 
structure). Any model derived from another contains the base 
model and it's structure exactly how any class that derives from 
any base class will contain the base class structure.

But since D does not know about models it makes makes it 
difficult to do such things and makes for ugly code. If the 
language and compiler could understand models we could extend 
models perfectly. We would only have to add whatever new behavior 
we want or change the behavior we want.

There are 3 main problems:

1. Because we cannot use multiple inheritance, this makes the 
code extremely verbose. We must use interfaces and the syntax 
becomes unnecessarily verbose, but it does work ultimately. Model 
inheritance has no issues with the diamond problem. Only one 
branch will ever be used(either through the base model or, when 
overridden, through the derived model).

2. We must override and alias members that ultimately do not need 
to be expressed. The compiler can figure it out if it understood 
what was being done.

3. Oop contravariance breaks the model logic and mixes 
dependencies. It is a non-issue in modeling. In D it requires us 
to cast everywhere. This is the main issue. You can see the issue 
at work using IsItTasty functions. It's simple, Contravariance 
prevents us staying with the derived model, we have to use the 
base model(for return types, same applies to arguments with 
covariance). But when we are in a derived model we are in it, we 
are using everything in the derived model that belongs to it(and 
behind them is the base model, but we do not directly refer to 
the base model), at least that would be the plan.

//f.IsItTasty; 		// Error: no property

The issue is with this line, it should just work, but D complains 
because it is trying to use the base model, yet, for all 
practical purposes the base model does not exist. The base model, 
in modeling, is completely occluded by the derived model(although 
maybe we would need a `supermodel.` type of accessor like we have 
with `super.`, although `super.` may work just fine)



Here is the code:


import std.stdio, std.traits;

struct ModelA
{
     // D only allows single inheritance, must use interfaces
     interface iAnimal
     {
         string Type();
		string Name();
         void Attack(iAnimal who);
         iFood LikesWhichFood();
     }

     interface iCat : iAnimal
     {
		void Meow();
     }

     interface iDog : iAnimal
     {
		void Bark();
     }
     interface iFood
     {

     }

     class Animal : iAnimal
     {
         void Attack(iAnimal who) { writeln(Name, " is attacking 
", who.Name, "!"); }
         string Type() { return "Unknown Animal Type"; }
		override string Name() { return "Unknown Animal"; }
		iFood LikesWhichFood() { writeln("Food D Type: ", 
fullyQualifiedName!iFood); return null; }					
     }

     class Cat : Animal, iCat
     {
		string name = "Unknown Cat";
         override string Type() { return "Cat"; }		
		override string Name() { return name; }
         void Meow() { writeln("Meow!"); }
		this() { }
		this(string n) { name = n; }
     }

	class Dog : Animal, iDog
     {
		string name = "Unknown Dog";
         override string Type() { return "Dog"; }		
		override string Name() { return name; }
         void Bark() { writeln("Bark!"); }
		this() { }
		this(string n) { name = n; }
     }


     class Food : iFood
     {

     }
}


// Model B, It is "derived" from A, meaning Model B could, in 
theory, substitute for Model A as long as everything is designed 
correctly
// In this case we will create a ViewModel, a gui framework for 
ModelA. We actually cannot do this naturally in D since it does 
not support multiple inheritance.
struct ModelB
{	
     interface iAnimal : ModelA.iAnimal
     {

     }

     interface iCat : iAnimal, ModelA.iAnimal
     {

     }

     interface iDog : iAnimal, ModelA.iAnimal
     {

     }
     interface iFood : ModelA.iFood
     {
		void IsItTasty();
     }

     class Animal : ModelA.Animal, iAnimal
     {

     }

     class Cat : ModelA.Cat, iAnimal, iCat // We need to derive 
from Animal, not iAnimal, to provide proper ModelB implementation 
of Animal
     {
		alias Attack = Animal.Attack;	// Required by D
		
		// In D, ModelA.Cat's implement is not provided as default, we 
have to reimplement everything. Or is Animal providing any 
implementation
         override string Type() { return super.Type; }		
		override string Name() { return super.Name; }
         override void Meow() { super.Meow; }
		void Attack(iAnimal who) { super.Attack(who); }
		override void Attack(ModelA.iAnimal who) { super.Attack(who); }
		override iFood LikesWhichFood() { writeln("Food D Type: ", 
fullyQualifiedName!iFood); return new Cabbage; }					
		this() { }
		this(string n) { name = n; }
		
     }

	class Dog : ModelA.Dog, iAnimal, iDog
     {
		alias Attack = Animal.Attack;	
         override string Type() { return super.Type; }		
		override string Name() { return super.Name; }
         override void Bark() { super.Bark; }
		void Attack(iAnimal who) { super.Attack(who); }
		override void Attack(ModelA.iAnimal who) { super.Attack(who); }
		override iFood LikesWhichFood() { writeln("Food D Type: ", 
fullyQualifiedName!iFood); return new Donuts; }					
		this() { }
		this(string n) { name = n; }
     }


     class Food : iFood
     {
		void IsItTasty() { writeln("Unknown Food"); }
     }

	class Donuts : Food
	{
		override void IsItTasty() { writeln("YUK!"); }
	}

	class Cabbage : Food
	{
		override void IsItTasty() { writeln("YUM!"); }
	}
}
void main()
{

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

		writeln(animal1.Name);
		writeln(animal2.Name);
		animal1.Attack(animal2);
		animal1.LikesWhichFood;
	}

	writeln("\n----------\n");

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

		writeln(animal1.Name);
		writeln(animal2.Name);
		animal1.Attack(animal2);
		auto f = animal1.LikesWhichFood;
		//f.IsItTasty; 		// Error: no property `IsItTasty` for type 
`Models.ModelA.iFood`. It should return a ModelB.iFood, we are 
inside ModelB, never any risk
		(cast(ModelB.iFood)f).IsItTasty;		// We can, of course, force 
it, but that is the rub, we don't have to, that is why we want to 
have a concept of a model, it tells the compiler that there is 
something more going on and it can reduce all this overhead. We 
can't even override this because of the contravariance rule.

	}

	writeln("\n----------\n");

	// This is the magic, ModelB is now substituted in Model A. It's 
basically still oop but our entire derived model is(or should be) 
used.
	// We can substitute the new model in all places where the old 
was used. This is the easy way to do ModelViewModel, we simply 
extend the model and add the view, no complex bridging, adapting, 
maintance, dependencies, etc.
	{
		ModelA.iAnimal animal1 = new ModelB.Cat("Super Mittens");
		ModelA.iAnimal animal2 = new ModelB.Dog("Super Sparky");

		writeln(animal1.Name);
		writeln(animal2.Name);
		animal1.Attack(animal2);
		animal1.LikesWhichFood;
		auto f = animal2.LikesWhichFood;
		//f.IsItTasty;	// This Error is ok, we are inside ModelA, 
ModelA would never use IsItTasty and it would be wrong to do 
so(it's only wrong because it should be impossible for ModelA to 
know about ModelB, else we create a dependency between models and 
really end up with one combined model rather than two separate 
models). But note that we could cast
		(cast(ModelB.iFood)f).IsItTasty;		// We can, of course, force 
it though(only because we know for a fact we are actually dealing 
with a ModelB disugised as a ModelA, this is generally not the 
case), but this then shows a dependency. Note that it is exactly 
like the above model though... but there is a huge difference. In 
the first case it is afe, in this case it is not.. and the only 
difference is the model we are working in.
	}
}


It should be noted that modeling is a higher abstraction but is 
effectively almost identical to standard oop. It's akin to 
elements and arrays of elements. It's virtually not that much 
more, except we do have to then add a few concepts such as 
indexing, insertion, etc.

In D, the code is very verbose, I guess some meta programming 
could reduce the verbosity quite a bit. Maybe it could even 
reduce it all(using mixin templates to provide the default 
implementation). I'm not sure if problem 3 could be fixed though, 
if it could then there would be no issues with modeling in D 
except verbosity, which, if meta program solved it then maybe 
there would be no issues in D.

If D had introduced a new concept called a model, which is sort 
of a collection of classes, then would could do something very 
simple to create a new model:

model ModelA
{
    class A { }
    class B : A { A foo; }
}

model ModelB : ModelA
{
    class A { B bar; } // bar is new functionality on top of 
ModelA.A. foo returns ModelB.A, not ModelA.A(fixes problem 3)
    // class B : A; // automatically uses ModelB.A and so has a 
member named bar, we don't have to change it if we don't want.
}

The model keyword looks at the specified hierarchy of ModelA(in 
this case just A, B and the inheritance morphism B : A) and we 
can then derive from the entire model... very similar to how we 
derive from classes.


auto m = new ModelA();

and

ModelA ma = new MoodelB();



I think D actually basically can do all this. If we replace model 
with class and inner classes could be derived recursively a few 
little extensions and we could just essentially use nested 
classes:

class ModelA
{
     class A { }
     class B : A { }
}

class ModelB : ModelA
{
     // The compiler extends inheritance to all classes of ModelA 
recursive
     // i.e. it adds class A : ModelA.A { } class B : A, ModelA.B 
{ } // Multiple inheritance allowed
     // Possibly allow direct modification such as override void 
B.bar(). rather than having to do it inside the class of B. Would 
make things a little less verbose.
}

Of course, to avoid it doing this on preexisting code we would 
introduce the model keyword... which would probably break a lot 
of code, so a better keyword would need to be used.


What is the use?

Imagine you write a calculator. You only write the business end, 
no gui, no interface, etc.

Now you want to create a gui for it. you create a new model that 
extends th calculator. You don't mix and match, don't create 
ModelViewModel(well, you are but using models you don't have to 
duplicate any code that is not needed.

model CalculatorGUI : Calculator
{
    // Add only graphical necessities. The gui can be used 
anywhere the calculator can, always providing a gui for any usage
}


E.g., suppose a bank around uses the Calculator to do math, you 
could substitute the CalculatorGUI for it and then get a gui 
version. Since CalculatorGUI is a Calculator, it will work just 
fine, again, this is just oop but applied in a more sophisticated 
way.


I have never seen a programming language use models like this. 
They all leave it up to the programmer to deal with keeping 
everything on the straight and narrow. Modeling is used 
everywhere and constantly. In fact, class inheritance is just 
very simple modeling.

I believe Haskell can do such things naturally but I don't know. 
D can almost D things naturally but it could be made very natural 
with a few modifications.
Jul 01 2019
next sibling parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Tuesday, 2 July 2019 at 01:21:56 UTC, CheeseWiz wrote:
 3. Oop contravariance breaks the model logic and mixes 
 dependencies. It is a non-issue in modeling. In D it requires 
 us to cast everywhere. This is the main issue. You can see the 
 issue at work using IsItTasty functions. It's simple, 
 Contravariance prevents us staying with the derived model, we 
 have to use the base model(for return types, same applies to 
 arguments with covariance). But when we are in a derived model 
 we are in it, we are using everything in the derived model that 
 belongs to it(and behind them is the base model, but we do not 
 directly refer to the base model), at least that would be the 
 plan.
Quite the opposite! Covariance actually saves you. struct ModelB { interface iAnimal : ModelA.iAnimal { override iFood LikesWhichFood(); }
Jul 02 2019
parent CheeseWiz <CheesyFritos gmail.com> writes:
On Tuesday, 2 July 2019 at 13:52:17 UTC, FeepingCreature wrote:
 On Tuesday, 2 July 2019 at 01:21:56 UTC, CheeseWiz wrote:
 3. Oop contravariance breaks the model logic and mixes 
 dependencies. It is a non-issue in modeling. In D it requires 
 us to cast everywhere. This is the main issue. You can see the 
 issue at work using IsItTasty functions. It's simple, 
 Contravariance prevents us staying with the derived model, we 
 have to use the base model(for return types, same applies to 
 arguments with covariance). But when we are in a derived model 
 we are in it, we are using everything in the derived model 
 that belongs to it(and behind them is the base model, but we 
 do not directly refer to the base model), at least that would 
 be the plan.
Quite the opposite! Covariance actually saves you. struct ModelB { interface iAnimal : ModelA.iAnimal { override iFood LikesWhichFood(); }
Ok, adding the follow does seem to work: interface iAnimal : ModelA.iAnimal { override iFood LikesWhichFood(); } then one has to do class Animal : ModelA.Animal, iAnimal { // Note the cast, but it is ok if necessary since at least it would isolate it. override iFood LikesWhichFood() { return cast(iFood)super.LikesWhichFood; } } The goal here is to avoid having to add all the extra plumbing. Imagine a real project with 100's of classes and having to override and cast everything just to get it to function. It seems excessive. Maybe meta programming can fix it?
Jul 02 2019
prev sibling parent reply Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 2 July 2019 at 01:21:56 UTC, CheeseWiz wrote:
 There are 3 main problems:

 1. Because we cannot use multiple inheritance, this makes the 
 code extremely verbose. We must use interfaces and the syntax 
 becomes unnecessarily verbose, but it does work ultimately. 
 Model inheritance has no issues with the diamond problem. Only 
 one branch will ever be used(either through the base model or, 
 when overridden, through the derived model).
I don't see where you used multiple inheritance. Turn everything into concrete/abstract classes and you should be fine.
 2. We must override and alias members that ultimately do not 
 need to be expressed. The compiler can figure it out if it 
 understood what was being done.
Are you referring to the "NotImplementedException" that proliferate most poorly designed abstractions?
 3. Oop contravariance breaks the model logic and mixes 
 dependencies. It is a non-issue in modeling. In D it requires 
 us to cast everywhere. This is the main issue. You can see the 
 issue at work using IsItTasty functions. It's simple, 
 Contravariance prevents us staying with the derived model, we 
 have to use the base model(for return types, same applies to 
 arguments with covariance). But when we are in a derived model 
 we are in it, we are using everything in the derived model that 
 belongs to it(and behind them is the base model, but we do not 
 directly refer to the base model), at least that would be the 
 plan.
With D support for both covariance and contravariance, you should be covered. You desired model behavior should just fall into place. Could you throw up a working example as a gist? Might take a hack at it.
Jul 02 2019
next sibling parent Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 2 July 2019 at 14:36:04 UTC, Jesse Phillips wrote:
 With D support for both covariance and contravariance, you 
 should be covered. You desired model behavior should just fall 
 into place.

 Could you throw up a working example as a gist? Might take a 
 hack at it.
Here is a related article https://he-the-great.livejournal.com/54436.html
Jul 02 2019
prev sibling parent reply CheeseWiz <CheesyFritos gmail.com> writes:
On Tuesday, 2 July 2019 at 14:36:04 UTC, Jesse Phillips wrote:
 On Tuesday, 2 July 2019 at 01:21:56 UTC, CheeseWiz wrote:
 There are 3 main problems:

 1. Because we cannot use multiple inheritance, this makes the 
 code extremely verbose. We must use interfaces and the syntax 
 becomes unnecessarily verbose, but it does work ultimately. 
 Model inheritance has no issues with the diamond problem. Only 
 one branch will ever be used(either through the base model or, 
 when overridden, through the derived model).
I don't see where you used multiple inheritance. Turn everything into concrete/abstract classes and you should be fine.
I didn't, D doesn't support MI. One has to inherit the base model and the derived model relationships, that is MI. interface iDog : iAnimal, ModelA.iAnimal { } class Animal : ModelA.Animal, iAnimal { override iFood LikesWhichFood() { return cast(iFood)super.LikesWhichFood; } ideally we could just do class Dog : Animal, ModelA.Animal and that is MI. It would simplify both models
 2. We must override and alias members that ultimately do not 
 need to be expressed. The compiler can figure it out if it 
 understood what was being done.
Are you referring to the "NotImplementedException" that proliferate most poorly designed abstractions?
alias Attack = Animal.Attack; // Required by D void Attack(iAnimal who) { super.Attack(who); } D gave me an error and said I must use the alias(first line), without I get an error about a missing override. Error: class `Models.ModelB.Cat` use of `Models.ModelA.Animal.Attack(iAnimal who)` is hidden by `Cat`; use `alias Attack = Animal.Attack;` to introduce base class overload set
 3. Oop contravariance breaks the model logic and mixes 
 dependencies. It is a non-issue in modeling. In D it requires 
 us to cast everywhere. This is the main issue. You can see the 
 issue at work using IsItTasty functions. It's simple, 
 Contravariance prevents us staying with the derived model, we 
 have to use the base model(for return types, same applies to 
 arguments with covariance). But when we are in a derived model 
 we are in it, we are using everything in the derived model 
 that belongs to it(and behind them is the base model, but we 
 do not directly refer to the base model), at least that would 
 be the plan.
With D support for both covariance and contravariance, you should be covered. You desired model behavior should just fall into place.
Yes, it seems that with the proper overrides it works. It is quite verbose, it would be amazing if all this stuff could be automated. It all is boilerplate code and requires for every model and every component of the model.
 Could you throw up a working example as a gist? Might take a 
 hack at it.
The OP contains a working example. Adding the overrides does solve problem 3 and so it is possible to have model inheritance in D! That is good news(I suppose it should be obvious since it's just normal inheritance)! Now the only goal is too make it simple to do. I imagine meta programming and mixin templates could solve this... Not sure though if one would need partial classes to make it work. (it would be ugly to also have to have a lot of mixin templates littered throughout) The goal would be to create something as simple as model A : B { // Add whatever extensions one wants, all plumbing is taken care of. }
Jul 02 2019
parent reply Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 2 July 2019 at 18:27:32 UTC, CheeseWiz wrote:
 
 The OP contains a working example.
I don't want to pull all the pieces together. Meta programing wouldn't likely help, there are too many rules about how your interface and inheritance needs to combine with the parent model that any meta programming would hide the intent. I still don't believe interfaces are needed, nor your example of multiple inheritance.
Jul 02 2019
parent reply Bert <Bert gmail.com> writes:
On Wednesday, 3 July 2019 at 04:58:00 UTC, Jesse Phillips wrote:
 On Tuesday, 2 July 2019 at 18:27:32 UTC, CheeseWiz wrote:
 
 The OP contains a working example.
I don't want to pull all the pieces together.
There are no pieces to put together. It is just a direct copy and paste. I pasted directly the source code in to the editor... you have to do is find the first place(which starts with import) and scroll do the last line(which is the last } of main). You are making it far more difficult than it is. The only difference is to get it truly working you have to add 2 lines of code to add the contravariance.
 Meta programing wouldn't likely help, there are too many rules 
 about how your interface and inheritance needs to combine with 
 the parent model that any meta programming would hide the 
 intent.
Maybe, maybe not. There are not too many rules though. It's simply providing the right overrides and such
 I still don't believe interfaces are needed, nor your example 
 of multiple inheritance.
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. Any any object in the derived model HAS TO derive from the base model and the parent in the derived model. That is the whole point. That is multiple inheritance. It can't be done any other way, but D only lets one inherent multiply using interfaces. You won't be able to get around that if this is going to be done using oop. Now, maybe one can hack things and not use inheritance between models and then force some type of substitution scheme that works... but that is for someone else to figure out. Everything actually works out in D, it's just verbose and cumbersome and for complex models it is error prone. Hence the only thing to do is find a better way to deal with it.
Jul 03 2019
parent reply Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
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
Jul 03 2019
parent reply Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
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
Jul 03 2019
parent reply Bert <Bert gmail.com> writes:
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.
Jul 03 2019
parent reply Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
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.
Jul 03 2019
parent reply CheeseWiz <CheesyFritos gmail.com> writes:
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.
Jul 05 2019
next sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
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
Jul 05 2019
next sibling parent CheeseWiz <CheesyFritos3 gmail.com> writes:
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.
Jul 05 2019
prev sibling parent reply CheeseWiz <CheesyFritos gmail.com> writes:
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.
Jul 06 2019
parent Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
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
Jul 07 2019
prev sibling parent reply Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
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.
Jul 07 2019
parent reply CheeseWiz <CheesyFritos gmail.com> writes:
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.
Jul 07 2019
parent Jesse Phillips <Jesse.K.Phillips+D gmail.com> writes:
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.
Jul 07 2019