www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Dropping the distinction between objects and references may hinder performance

reply Lodjer <Lodjer_member pathlink.com> writes:
D looks like a great language.  It is a good thing to finaly see a modern object
oriented language that is not overly bloated.  Especially the way D's Garbage
collector works, it is not the one and only deallocation method and we have
enough control over it help increase it's performance.  The auto keyword is a
good example, it prevent the waste of CPU cycles of scanning for references to
local objects.
However, there is one problem that other modern oo languages have that D has too
:  All objects are by reference.  This can hinder performance and increase
memory usage.  The problem occurs when you do composition (having an object as a
class member).  To put an instance of classB in classA, in C++ you would write :

class classA
{
private :
classB objectB;
//...
public :
void functionA()
{
objectB.functionB();
}
};

In this example, objectB is part of any instance of classA, not it's reference.
To access objectB in functionA(), all that the compiler have to do is add the
distance between the beginning of classA and the position of objectB to the This
pointer.  Howerver, in D, since all objects are by reference, the corresponding
code would not place objectB inside instances of classA, but a reference to
objectB.  objectB would be somewhere else in memory.  Not only does this would
cause overhead at initialisation and destruction of any instance of classA, but
it would also cause overhead at any access to objectB.  In D, to access objectB
in functionA(), the compiler would have to add the distance between the
beginning of classA and the position of the reference to objectB to the This
pointer and then read the address in the reference.  It would also use more
memory for the reference itself.

There should be some mean in D, like a keyword for example, to specifiy that you
want objectB to be part of an instance of classA.

That said, D does look like a very promising successor to C/C++, C++ being my
favorite language yet.  I hope this issue will be solved before D reachs version
1.0.  Because that would certainly make it become my new favorite language.
Oct 18 2004
next sibling parent reply Ben Hinkle <bhinkle4 juno.com> writes:
Lodjer wrote:

 D looks like a great language.  It is a good thing to finaly see a modern
 object
 oriented language that is not overly bloated.  Especially the way D's
 Garbage collector works, it is not the one and only deallocation method
 and we have
 enough control over it help increase it's performance.  The auto keyword
 is a good example, it prevent the waste of CPU cycles of scanning for
 references to local objects.
 However, there is one problem that other modern oo languages have that D
 has too
 :  All objects are by reference.  This can hinder performance and increase
 memory usage.  The problem occurs when you do composition (having an
 object as a
 class member).  To put an instance of classB in classA, in C++ you would
 write :
 
 class classA
 {
 private :
 classB objectB;
 //...
 public :
 void functionA()
 {
 objectB.functionB();
 }
 };
 
 In this example, objectB is part of any instance of classA, not it's
 reference. To access objectB in functionA(), all that the compiler have to
 do is add the distance between the beginning of classA and the position of
 objectB to the This
 pointer.  Howerver, in D, since all objects are by reference, the
 corresponding code would not place objectB inside instances of classA, but
 a reference to
 objectB.  objectB would be somewhere else in memory.  Not only does this
 would cause overhead at initialisation and destruction of any instance of
 classA, but
 it would also cause overhead at any access to objectB.  In D, to access
 objectB in functionA(), the compiler would have to add the distance
 between the beginning of classA and the position of the reference to
 objectB to the This
 pointer and then read the address in the reference.  It would also use
 more memory for the reference itself.
 
 There should be some mean in D, like a keyword for example, to specifiy
 that you want objectB to be part of an instance of classA.
 
 That said, D does look like a very promising successor to C/C++, C++ being
 my
 favorite language yet.  I hope this issue will be solved before D reachs
 version
 1.0.  Because that would certainly make it become my new favorite
 language.

It would probably get pretty messy trying to keep track of reference semantics vs value semantics. How would assignment to objectB work: by reference or value? I assume by value since there isn't any reference. And in that case the "slicing problem" comes up where one can assign a subclass of classB to objectB and wipe out all the subclass information. Here are two options that would work today: 1) make classB a struct instead of a class 2) make classB a template and mix it in. For example template B { int x; functionB() {...} } class classA { private : mixin B; //... public : void functionA() { functionB(); x = 10; } };
Oct 18 2004
parent reply Lodjer <Lodjer_member pathlink.com> writes:
In article <cl1i3t$1aul$1 digitaldaemon.com>, Ben Hinkle says...
Lodjer wrote:

 D looks like a great language.  It is a good thing to finaly see a modern
 object
 oriented language that is not overly bloated.  Especially the way D's
 Garbage collector works, it is not the one and only deallocation method
 and we have
 enough control over it help increase it's performance.  The auto keyword
 is a good example, it prevent the waste of CPU cycles of scanning for
 references to local objects.
 However, there is one problem that other modern oo languages have that D
 has too
 :  All objects are by reference.  This can hinder performance and increase
 memory usage.  The problem occurs when you do composition (having an
 object as a
 class member).  To put an instance of classB in classA, in C++ you would
 write :
 
 class classA
 {
 private :
 classB objectB;
 //...
 public :
 void functionA()
 {
 objectB.functionB();
 }
 };
 
 In this example, objectB is part of any instance of classA, not it's
 reference. To access objectB in functionA(), all that the compiler have to
 do is add the distance between the beginning of classA and the position of
 objectB to the This
 pointer.  Howerver, in D, since all objects are by reference, the
 corresponding code would not place objectB inside instances of classA, but
 a reference to
 objectB.  objectB would be somewhere else in memory.  Not only does this
 would cause overhead at initialisation and destruction of any instance of
 classA, but
 it would also cause overhead at any access to objectB.  In D, to access
 objectB in functionA(), the compiler would have to add the distance
 between the beginning of classA and the position of the reference to
 objectB to the This
 pointer and then read the address in the reference.  It would also use
 more memory for the reference itself.
 
 There should be some mean in D, like a keyword for example, to specifiy
 that you want objectB to be part of an instance of classA.
 
 That said, D does look like a very promising successor to C/C++, C++ being
 my
 favorite language yet.  I hope this issue will be solved before D reachs
 version
 1.0.  Because that would certainly make it become my new favorite
 language.

It would probably get pretty messy trying to keep track of reference semantics vs value semantics. How would assignment to objectB work: by reference or value? I assume by value since there isn't any reference. And in that case the "slicing problem" comes up where one can assign a subclass of classB to objectB and wipe out all the subclass information. Here are two options that would work today: 1) make classB a struct instead of a class 2) make classB a template and mix it in. For example template B { int x; functionB() {...} } class classA { private : mixin B; //... public : void functionA() { functionB(); x = 10; } };

There are two very simple solutions to this problem. Simply either make assigning a subclass of classB to objectB illegal. Or, even simpler, make reassigning objectB illegal, like for auto variables. There should be no assiging "objectB = new classB();" in the initialsiation either, like in C++, preventing assingnement of a subclasse or superclasse of classB to objectB; To avoid further problems with reassignement of classes, having a class by value could (and should) be made legal ONLY for class members.
Oct 18 2004
parent reply Ben Hinkle <bhinkle4 juno.com> writes:
Lodjer wrote:

 In article <cl1i3t$1aul$1 digitaldaemon.com>, Ben Hinkle says...
Lodjer wrote:

 D looks like a great language.  It is a good thing to finaly see a
 modern object
 oriented language that is not overly bloated.  Especially the way D's
 Garbage collector works, it is not the one and only deallocation method
 and we have
 enough control over it help increase it's performance.  The auto keyword
 is a good example, it prevent the waste of CPU cycles of scanning for
 references to local objects.
 However, there is one problem that other modern oo languages have that D
 has too
 :  All objects are by reference.  This can hinder performance and
 :  increase
 memory usage.  The problem occurs when you do composition (having an
 object as a
 class member).  To put an instance of classB in classA, in C++ you would
 write :
 
 class classA
 {
 private :
 classB objectB;
 //...
 public :
 void functionA()
 {
 objectB.functionB();
 }
 };
 
 In this example, objectB is part of any instance of classA, not it's
 reference. To access objectB in functionA(), all that the compiler have
 to do is add the distance between the beginning of classA and the
 position of objectB to the This
 pointer.  Howerver, in D, since all objects are by reference, the
 corresponding code would not place objectB inside instances of classA,
 but a reference to
 objectB.  objectB would be somewhere else in memory.  Not only does this
 would cause overhead at initialisation and destruction of any instance
 of classA, but
 it would also cause overhead at any access to objectB.  In D, to access
 objectB in functionA(), the compiler would have to add the distance
 between the beginning of classA and the position of the reference to
 objectB to the This
 pointer and then read the address in the reference.  It would also use
 more memory for the reference itself.
 
 There should be some mean in D, like a keyword for example, to specifiy
 that you want objectB to be part of an instance of classA.
 
 That said, D does look like a very promising successor to C/C++, C++
 being my
 favorite language yet.  I hope this issue will be solved before D reachs
 version
 1.0.  Because that would certainly make it become my new favorite
 language.

It would probably get pretty messy trying to keep track of reference semantics vs value semantics. How would assignment to objectB work: by reference or value? I assume by value since there isn't any reference. And in that case the "slicing problem" comes up where one can assign a subclass of classB to objectB and wipe out all the subclass information. Here are two options that would work today: 1) make classB a struct instead of a class 2) make classB a template and mix it in. For example template B { int x; functionB() {...} } class classA { private : mixin B; //... public : void functionA() { functionB(); x = 10; } };

There are two very simple solutions to this problem. Simply either make assigning a subclass of classB to objectB illegal. Or, even simpler, make reassigning objectB illegal, like for auto variables. There should be no assiging "objectB = new classB();" in the initialsiation either, like in C++, preventing assingnement of a subclasse or superclasse of classB to objectB; To avoid further problems with reassignement of classes, having a class by value could (and should) be made legal ONLY for class members.

That might not be so bad, actually. It's almost like one should be able to "struct"ize a given class. This process would define a struct with the same members as the class (minus constructors and destructors) but with struct semantics. Making up a new property off the top of my head each class type could get a "struct" property that would return a new type with struct semantics. So your example would be class classA { private : classB.struct objectB; //... public : void functionA() { objectB.functionB(); } }; I'm warming up to your idea :-) -Ben
Oct 18 2004
next sibling parent Martin <Martin_member pathlink.com> writes:
class classA
{
  private :
  classB.struct objectB;
  //...
  public :
  void functionA()
  {
    objectB.functionB();
  }
};

Like the idea! In article <cl1v4h$1map$1 digitaldaemon.com>, Ben Hinkle says...
Lodjer wrote:

 In article <cl1i3t$1aul$1 digitaldaemon.com>, Ben Hinkle says...
Lodjer wrote:

 D looks like a great language.  It is a good thing to finaly see a
 modern object
 oriented language that is not overly bloated.  Especially the way D's
 Garbage collector works, it is not the one and only deallocation method
 and we have
 enough control over it help increase it's performance.  The auto keyword
 is a good example, it prevent the waste of CPU cycles of scanning for
 references to local objects.
 However, there is one problem that other modern oo languages have that D
 has too
 :  All objects are by reference.  This can hinder performance and
 :  increase
 memory usage.  The problem occurs when you do composition (having an
 object as a
 class member).  To put an instance of classB in classA, in C++ you would
 write :
 
 class classA
 {
 private :
 classB objectB;
 //...
 public :
 void functionA()
 {
 objectB.functionB();
 }
 };
 
 In this example, objectB is part of any instance of classA, not it's
 reference. To access objectB in functionA(), all that the compiler have
 to do is add the distance between the beginning of classA and the
 position of objectB to the This
 pointer.  Howerver, in D, since all objects are by reference, the
 corresponding code would not place objectB inside instances of classA,
 but a reference to
 objectB.  objectB would be somewhere else in memory.  Not only does this
 would cause overhead at initialisation and destruction of any instance
 of classA, but
 it would also cause overhead at any access to objectB.  In D, to access
 objectB in functionA(), the compiler would have to add the distance
 between the beginning of classA and the position of the reference to
 objectB to the This
 pointer and then read the address in the reference.  It would also use
 more memory for the reference itself.
 
 There should be some mean in D, like a keyword for example, to specifiy
 that you want objectB to be part of an instance of classA.
 
 That said, D does look like a very promising successor to C/C++, C++
 being my
 favorite language yet.  I hope this issue will be solved before D reachs
 version
 1.0.  Because that would certainly make it become my new favorite
 language.

It would probably get pretty messy trying to keep track of reference semantics vs value semantics. How would assignment to objectB work: by reference or value? I assume by value since there isn't any reference. And in that case the "slicing problem" comes up where one can assign a subclass of classB to objectB and wipe out all the subclass information. Here are two options that would work today: 1) make classB a struct instead of a class 2) make classB a template and mix it in. For example template B { int x; functionB() {...} } class classA { private : mixin B; //... public : void functionA() { functionB(); x = 10; } };

There are two very simple solutions to this problem. Simply either make assigning a subclass of classB to objectB illegal. Or, even simpler, make reassigning objectB illegal, like for auto variables. There should be no assiging "objectB = new classB();" in the initialsiation either, like in C++, preventing assingnement of a subclasse or superclasse of classB to objectB; To avoid further problems with reassignement of classes, having a class by value could (and should) be made legal ONLY for class members.

That might not be so bad, actually. It's almost like one should be able to "struct"ize a given class. This process would define a struct with the same members as the class (minus constructors and destructors) but with struct semantics. Making up a new property off the top of my head each class type could get a "struct" property that would return a new type with struct semantics. So your example would be class classA { private : classB.struct objectB; //... public : void functionA() { objectB.functionB(); } }; I'm warming up to your idea :-) -Ben

Oct 19 2004
prev sibling parent reply Lodjer <Lodjer_member pathlink.com> writes:
In article <cl1v4h$1map$1 digitaldaemon.com>, Ben Hinkle says...
That might not be so bad, actually. It's almost like one should be able to
"struct"ize a given class. This process would define a struct with the same
members as the class (minus constructors and destructors) but with struct
semantics. Making up a new property off the top of my head each class type
could get a "struct" property that would return a new type with struct
semantics. So your example would be

class classA
{
  private :
  classB.struct objectB;
  //...
  public :
  void functionA()
  {
    objectB.functionB();
  }
};

I'm warming up to your idea :-)

-Ben

This sounds like a very good idea to me. Especially if the struct defined from the "struct"ized class is defined with it's members in the same order and with the same alignement that they are in the "revised and aligned" version of the class that the compiler generate, including the virtual table pointer (wich should be hidden for safety of course). This way, the compiler would not have to generate a duplicate of the code of the methodes of the class, since there would be no difference between a reference to a "normal" object and a "struct"ized object. It would also allow placing the pointer to a "struct"ized object in a "normal" object reference. I don't see why you want to drop the constructors and destructors do. Of course they should not be called juste anywhere. The destructor could be called implicitly when the program live the scope of the "struct"ized object when it is a local object, or when the destructor of the parent class is called when the it is a class member. The constructor could be called either implicitly or explicitly at declaration or along with the "super.this(...)" of the parent class. For exemple : class classA { private : classB.struct objectB1; // Constructor called implicitly. classB.struct objectB2( /* Insert constructor parameters */ ); // Constructor called explicitly at declaration. classB.struct objectB3; //... public : this() { super.this( /* Insert constructor parameters */ ); objectB3.this( /* Insert constructor parameters */ ); //Constructor called explicitly in the parent class' constructor. } void functionA() { objectB.functionB(); someFakeFunction( objectB ); // Reference to "struct"ized classB passed seemlessly as a "normal" object reference. } }
Oct 19 2004
parent reply Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
Lodjer wrote:

<snip>
 I don't see why you want to drop the constructors and destructors do.  Of
course
 they should not be called juste anywhere.  The destructor could be called
 implicitly when the program live the scope of the "struct"ized object when it
is
 a local object, or when the destructor of the parent class is called when the
it
 is a class member.  The constructor could be called either implicitly or
 explicitly at declaration or along with the "super.this(...)" of the parent
 class.

Would this mean that we can get a better handle on the order of destruction of "struct"ized objects? In particular, would the garbage collector be able to call the destructor of these kinds of objects before the owner is destructed? That would be a real advantage and save a lot of headaches. To me that would be a stronger argument than the performance issue. Bastiaan.
Oct 19 2004
parent Lodjer <Lodjer_member pathlink.com> writes:
In article <cl3anc$3mm$1 digitaldaemon.com>, Bastiaan Veelo says...
Lodjer wrote:

<snip>
 I don't see why you want to drop the constructors and destructors do.  Of
course
 they should not be called juste anywhere.  The destructor could be called
 implicitly when the program live the scope of the "struct"ized object when it
is
 a local object, or when the destructor of the parent class is called when the
it
 is a class member.  The constructor could be called either implicitly or
 explicitly at declaration or along with the "super.this(...)" of the parent
 class.

Would this mean that we can get a better handle on the order of destruction of "struct"ized objects? In particular, would the garbage collector be able to call the destructor of these kinds of objects before the owner is destructed? That would be a real advantage and save a lot of headaches. To me that would be a stronger argument than the performance issue. Bastiaan.

The garbage collector would have no need to call the desctructor of "struct"ized objects when they are part of a owner class. Simply because the destructor of the owner could call it implicitly, either before the user's destructor or after. Personnaly I would prefer after, because the destructor may still need to use these objects one last time. Also, the "struct"ized objects wich are part of a owner class would be deleted all at once with the owner class, since they would be part of the owner class, instead of being deleted separatly. Well, of course, this is the way I see it, D's designers may see it some other way.
Oct 19 2004
prev sibling parent James McComb <ned jamesmccomb.id.au> writes:
Lodjer wrote:

 There should be some mean in D, like a keyword for example, to specifiy that
you
 want objectB to be part of an instance of classA.

Similar functionality exists in Eiffel, where it is called /expanded classes/. Walter borrowed Design By Contract from Eiffel, but he didn't borrow expanded classes. Maybe if there was the demand... James McComb
Oct 18 2004