www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Real OOP with D

reply "Ozan" <ozan.sueel gmail.com> writes:
Hi

Working with objectoriented concepts results often in large trees 
of related classes. Every instance of a class knows his methods 
and data.  An example like following would work:

import std.stdio;
class Family { }
class Dad : Family { void greeting() { writeln("I'm dad"); } }
class Boy : Family { void greeting() { writeln("I'm daddy's 
boy"); } }
void main() {
writeln("Father and son");
Dad father = new Dad;
Family son = new Boy;
father.greeting;
son.greeting;
}

The critical point is using a variable of type Family for an 
instance of Boy. Class Family covers the greeting method of Boy. 
In real OOP that would not be a problem, because the access point 
of view starts with the object. In D, it starts with the class 
definition.

Is there any way to get real OOP with D?

Regards,  Ozan
Aug 16 2015
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/16/2015 10:57 PM, Ozan wrote:

 Working with objectoriented concepts results often in large trees of
 related classes. Every instance of a class knows his methods and data.
 An example like following would work:

 import std.stdio;
 class Family { }
From the way you use it below, a better name for that class would be FamilyMember but I get the point.
 class Dad : Family { void greeting() { writeln("I'm dad"); } }
 class Boy : Family { void greeting() { writeln("I'm daddy's boy"); } }
 void main() {
 writeln("Father and son");
 Dad father = new Dad;
 Family son = new Boy;
 father.greeting;
 son.greeting;
What you mean is that the call above causes a compilation error: Error: no property 'greeting' for type 'deneme.Family'
 }

 The critical point is using a variable of type Family for an instance of
 Boy. Class Family covers the greeting method of Boy. In real OOP that
 would not be a problem, because the access point of view starts with the
 object.
My experience with OOP is limited to C++ and D. I think what you are describing is how dynamically typed languages work. It is impossible in compiled languages like C++ and D. When a type is used in an expression, the compiler ensures that the call is bound to a function.
 In D, it starts with the class definition.
Actually, 'interface' is a better fit in most cases: interface FamilyMember { // ... } class Dad : FamilyMember { // ... }
 Is there any way to get real OOP with D?

 Regards,  Ozan
Ali
Aug 16 2015
parent reply "Ozan" <ozan.sueel gmail.com> writes:
On Monday, 17 August 2015 at 06:08:35 UTC, Ali Çehreli wrote:
 On 08/16/2015 10:57 PM, Ozan wrote:
[...]
 From the way you use it below, a better name for that class 
 would be FamilyMember but I get the point.
Yes, you're right.

[...]
 father.greeting;
 son.greeting;
What you mean is that the call above causes a compilation error: Error: no property 'greeting' for type 'deneme.Family'
 }
[...]
 My experience with OOP is limited to C++ and D. I think what 
 you are describing is how dynamically typed languages work. It 
 is impossible in compiled languages like C++ and D. When a type 
 is used in an expression, the compiler ensures that the call is 
 bound to a function.

 In D, it starts with the class definition.
Actually, 'interface' is a better fit in most cases: interface FamilyMember { // ... } class Dad : FamilyMember { // ... }
[...]
 Ali
Interfaces are very helpful to avoid large inheritance trees in OOP. On the other hand, there are not designed as workarounds for OOP implementation problems. The kind of OOP in D is a classical way to handle it. Dynamic languages tries to close the gap between theoretical and practical OOP for the price of speed. I think that Adam's jsvar idea is a great way to bring more flexibility into D. The same in OOP would be also great. Regards, Ozan
Aug 17 2015
next sibling parent "Kagamin" <spam here.lot> writes:
On Tuesday, 18 August 2015 at 06:03:09 UTC, Ozan wrote:
 I think that Adam's jsvar idea is a great way to bring more 
 flexibility into D. The same in OOP would be also great.
Dynamic typing in D can be emulated in the same way jsvar and Variant do it. If jsvar doesn't support it, you can look into libraries like luad, which AFAIK can generate dynamic wrappers for static types, I suppose there was something similar for IDispatch.
Aug 18 2015
prev sibling parent "Kagamin" <spam here.lot> writes:
On Tuesday, 18 August 2015 at 06:03:09 UTC, Ozan wrote:
 I think that Adam's jsvar idea is a great way to bring more 
 flexibility into D. The same in OOP would be also great.
Looks like jsvar can invoke opCall method for wrapped object: https://github.com/adamdruppe/arsd/blob/master/jsvar.d#L729 you can extend it to support invocation of other methods.
Aug 18 2015
prev sibling next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 17/08/2015 5:57 p.m., Ozan wrote:
 Hi

 Working with objectoriented concepts results often in large trees of
 related classes. Every instance of a class knows his methods and data.
 An example like following would work:

 import std.stdio;
 class Family { }
 class Dad : Family { void greeting() { writeln("I'm dad"); } }
 class Boy : Family { void greeting() { writeln("I'm daddy's boy"); } }
 void main() {
 writeln("Father and son");
 Dad father = new Dad;
 Family son = new Boy;
 father.greeting;
 son.greeting;
 }

 The critical point is using a variable of type Family for an instance of
 Boy. Class Family covers the greeting method of Boy. In real OOP that
 would not be a problem, because the access point of view starts with the
 object. In D, it starts with the class definition.

 Is there any way to get real OOP with D?

 Regards,  Ozan
import std.stdio; abstract class Family { void greeting(); } class Dad : Family { void greeting() { writeln("I'm dad"); } } class Boy : Family { void greeting() { writeln("I'm daddy's boy"); } } void main() { Family dad = new Dad; Family boy = new Boy; dad.greeting; boy.greeting; } I'm confused how this isn't real OOP?
Aug 16 2015
parent "Ozan" <ozan.sueel gmail.com> writes:
On Monday, 17 August 2015 at 06:10:38 UTC, Rikki Cattermole wrote:
 On 17/08/2015 5:57 p.m., Ozan wrote:
 Hi
[...]
 import std.stdio;
 abstract class Family { void greeting(); }
 class Dad : Family { void greeting() { writeln("I'm dad"); } }
 class Boy : Family { void greeting() { writeln("I'm daddy's 
 boy"); } }

 void main() {
 	Family dad = new Dad;
 	Family boy = new Boy;
 	dad.greeting;
 	boy.greeting;
 }

 I'm confused how this isn't real OOP?
Replace 'real' with 'theoretical' OOP. Every instance of a class (object) is like an independent black box. Every public message (method / function) of the class definition could be called when ever you want. Variables are like pointers to objects. With inheritance and overriding you're losing in class type implementations of OOP a lot of 'theoretical' flexibility. I was asking for a possibility to avoid this. Regards Ozan
Aug 17 2015
prev sibling parent reply "BBasile" <bb.temp gmx.com> writes:
On Monday, 17 August 2015 at 05:57:52 UTC, Ozan wrote:
 Hi

 Working with objectoriented concepts results often in large 
 trees of related classes. Every instance of a class knows his 
 methods and data.  An example like following would work:

 import std.stdio;
 class Family { }
 class Dad : Family { void greeting() { writeln("I'm dad"); } }
 class Boy : Family { void greeting() { writeln("I'm daddy's 
 boy"); } }
 void main() {
 writeln("Father and son");
 Dad father = new Dad;
 Family son = new Boy;
 father.greeting;
 son.greeting;
 }

 The critical point is using a variable of type Family for an 
 instance of Boy. Class Family covers the greeting method of 
 Boy. In real OOP that would not be a problem, because the 
 access point of view starts with the object. In D, it starts 
 with the class definition.

 Is there any way to get real OOP with D?

 Regards,  Ozan
Can you name an OOP oriented language that allows this ? Your example is eroneous OOP. The 2 other answers you 've got (the first using an interface and the second using an abstract class) are valid OOP. One of the fundamental concept OOP is that a function defined in a class exists also in its subclasses. So how do you expect `greeting()` to exist in Family if it's only defined in its sub-classes ? You can verify that with the 'Liskov substitution principle' (https://en.wikipedia.org/wiki/Liskov_substitution_principle). Actually your sample violates this principle.
Aug 16 2015
parent reply "Ozan" <ozan.sueel gmail.com> writes:
On Monday, 17 August 2015 at 06:59:51 UTC, BBasile wrote:
 On Monday, 17 August 2015 at 05:57:52 UTC, Ozan wrote:
 Hi
[...]
 Is there any way to get real OOP with D?

 Regards,  Ozan
Can you name an OOP oriented language that allows this ? Your example is eroneous OOP. The 2 other answers you 've got (the first using an interface and the second using an abstract class) are valid OOP. One of the fundamental concept OOP is that a function defined in a class exists also in its subclasses. So how do you expect `greeting()` to exist in Family if it's only defined in its sub-classes ? You can verify that with the 'Liskov substitution principle' (https://en.wikipedia.org/wiki/Liskov_substitution_principle). Actually your sample violates this principle.
Languages like Groovy or JavaScript (with the help of frameworks ;-) And I believe many more the newer ones. But that's not the point. And... This was not a criticism against D (... "bad D, has no understanding of OOP. Boahh" ;-) It was only a question about handling of a typical OOP problem in a class-typed implementation of OOP like D has. Thanks to every existing or new creative programming language, today we have so many other ways to solve our programming problems. Regards Ozan
Aug 17 2015
parent reply "BBasile" <bb.temp gmx.com> writes:
On Tuesday, 18 August 2015 at 06:27:53 UTC, Ozan wrote:
 On Monday, 17 August 2015 at 06:59:51 UTC, BBasile wrote:
 On Monday, 17 August 2015 at 05:57:52 UTC, Ozan wrote:
 Hi
[...]
 Is there any way to get real OOP with D?

 Regards,  Ozan
Can you name an OOP oriented language that allows this ? Your example is eroneous OOP. The 2 other answers you 've got (the first using an interface and the second using an abstract class) are valid OOP. One of the fundamental concept OOP is that a function defined in a class exists also in its subclasses. So how do you expect `greeting()` to exist in Family if it's only defined in its sub-classes ? You can verify that with the 'Liskov substitution principle' (https://en.wikipedia.org/wiki/Liskov_substitution_principle). Actually your sample violates this principle.
Languages like Groovy or JavaScript (with the help of frameworks ;-) And I believe many more the newer ones. But that's not the point. And... This was not a criticism against D (... "bad D, has no understanding of OOP. Boahh" ;-) It was only a question about handling of a typical OOP problem in a class-typed implementation of OOP like D has. Thanks to every existing or new creative programming language, today we have so many other ways to solve our programming problems. Regards Ozan
You example is not valid strongly-typed OOP. In D you could do something similar but not with the OO paradigm but rather with compile-time refexion (introspection): --- import std.stdio; static bool isFamilyMember(T)() { import std.traits: isCallable; return __traits(hasMember, T, "greeting"); } void FamilyMemberSayHello(T)(ref T t) { static if (isFamilyMember!T) t.greeting; } struct Dad{ void greeting(){"hello from a Dad".writeln;} } struct Boy{ void greeting(){"hello from a Boy".writeln;} } struct IdiotDuBled{} void main() { auto dad = new Dad; auto boy = new Boy; auto idiotDuBled = new IdiotDuBled; FamilyMemberSayHello(dad); FamilyMemberSayHello(boy); FamilyMemberSayHello(idiotDuBled); } --- The idea is rather to check at compile time if a variable will have the "trait" which characterizes a FamilyMember, without using inheritence.
Aug 18 2015
parent "Caspar" <Caspar Kielwein.de> writes:
On Tuesday, 18 August 2015 at 07:19:02 UTC, BBasile wrote:
 On Tuesday, 18 August 2015 at 06:27:53 UTC, Ozan wrote:
 On Monday, 17 August 2015 at 06:59:51 UTC, BBasile wrote:
 On Monday, 17 August 2015 at 05:57:52 UTC, Ozan wrote:
 Hi
[...]
 Is there any way to get real OOP with D?

 Regards,  Ozan
Can you name an OOP oriented language that allows this ? Your example is eroneous OOP. The 2 other answers you 've got (the first using an interface and the second using an abstract class) are valid OOP. One of the fundamental concept OOP is that a function defined in a class exists also in its subclasses. So how do you expect `greeting()` to exist in Family if it's only defined in its sub-classes ? You can verify that with the 'Liskov substitution principle' (https://en.wikipedia.org/wiki/Liskov_substitution_principle). Actually your sample violates this principle.
Languages like Groovy or JavaScript (with the help of frameworks ;-) And I believe many more the newer ones. But that's not the point. And... This was not a criticism against D (... "bad D, has no understanding of OOP. Boahh" ;-) It was only a question about handling of a typical OOP problem in a class-typed implementation of OOP like D has. Thanks to every existing or new creative programming language, today we have so many other ways to solve our programming problems. Regards Ozan
You example is not valid strongly-typed OOP. In D you could do something similar but not with the OO paradigm but rather with compile-time refexion (introspection): --- import std.stdio; static bool isFamilyMember(T)() { import std.traits: isCallable; return __traits(hasMember, T, "greeting"); } void FamilyMemberSayHello(T)(ref T t) { static if (isFamilyMember!T) t.greeting; } struct Dad{ void greeting(){"hello from a Dad".writeln;} } struct Boy{ void greeting(){"hello from a Boy".writeln;} } struct IdiotDuBled{} void main() { auto dad = new Dad; auto boy = new Boy; auto idiotDuBled = new IdiotDuBled; FamilyMemberSayHello(dad); FamilyMemberSayHello(boy); FamilyMemberSayHello(idiotDuBled); } --- The idea is rather to check at compile time if a variable will have the "trait" which characterizes a FamilyMember, without using inheritence.
I believe D allows what you want to do using generic programming. Being a compiled and strongly typed language, the information about the type, needs to be available during compilation, but this makes no difference from a theoretic OOP view. BBasiles example can also be done without the trait. Then the check for greeting() will be done by the compiler. void FamilyMemberSayHello(T)(ref T t) { t.greeting; } struct Dad{ void greeting(){"hello from a Dad".writeln;} } struct Boy{ void greeting(){"hello from a Boy".writeln;} } struct IdiotDuBled{} void main() { auto dad = new Dad; auto boy = new Boy; auto idiotDuBled = new IdiotDuBled; FamilyMemberSayHello(dad); FamilyMemberSayHello(boy); FamilyMemberSayHello(idiotDuBled); //will not compile } The OOP Model of D is fairly close to that of Eiffel which I consider pretty pure Object Oriented. The only exception is multiple inheritance, which I do not miss at all. In my Opinion D is a great language for Object Oriented Design and Programming. It awesomely supports Contracts and Constraint Generics, which many languages lack. I never missed multiple inheritance, as I was able to cover all my use cases with mixins. The support for functional programming and CTFE allows to elegantly handle the cases, where inheritance based OOP feels awkward. Actually I urge all the people who say: "Smalltalk was the last (only) good OOP language!" to try out D.
Aug 18 2015