www.digitalmars.com         C & C++   DMDScript  

D - Size of type bug in D?

reply "christopher diggins" <cdiggins users.sourceforge.net> writes:
I can't get the real size of a class:

  class FuBar {
    int m1, m2;
    float m3;
  }

  int main() {
    FuBar x = new FuBar;
    printf("sizeof FuBar = %d\n", FuBar.size);
    printf("sizeof FuBar = %d\n", FuBar.sizeof);
    printf("sizeof FuBar = %d\n", x.size);
    printf("sizeof FuBar = %d\n", x.sizeof);
    return 0;
  }

All of these calls output 4 bytes.

-- 
Christopher Diggins
http://www.cdiggins.com
http://www.heron-language.com
Apr 09 2004
parent reply "Walter" <walter digitalmars.com> writes:
"christopher diggins" <cdiggins users.sourceforge.net> wrote in message
news:c56iq9$2pmp$1 digitaldaemon.com...
 I can't get the real size of a class:

   class FuBar {
     int m1, m2;
     float m3;
   }

   int main() {
     FuBar x = new FuBar;
     printf("sizeof FuBar = %d\n", FuBar.size);
     printf("sizeof FuBar = %d\n", FuBar.sizeof);
     printf("sizeof FuBar = %d\n", x.size);
     printf("sizeof FuBar = %d\n", x.sizeof);
     return 0;
   }

 All of these calls output 4 bytes.

Right. That's because you're getting the size of a reference to a class object. To get the size of the object itself: x.classinfo.init.length
Apr 09 2004
parent reply "christopher diggins" <cdiggins users.sourceforge.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:c56p1b$2lj$2 digitaldaemon.com...
 "christopher diggins" <cdiggins users.sourceforge.net> wrote in message
 news:c56iq9$2pmp$1 digitaldaemon.com...
 I can't get the real size of a class:


 Right. That's because you're getting the size of a reference to a class
 object. To get the size of the object itself:
     x.classinfo.init.length

Thank you for that Walter. So armed with that new knowledge here is a very short example program: interface IFu { void Fu(); } interface IBar { void Bar(); } class Fu : IFu { void Fu() { printf("fubar fu\n"); }; } class FuBar : IFu, IBar { void Fu() { printf("fubar fu\n"); }; void Bar() { printf("fubar bar\n"); }; } class Empty { } int main() { Empty x = new Empty; Fu y = new Fu; FuBar z = new FuBar; printf("sizeof Empty = %d\n", x.classinfo.init.length); // outputs 8 printf("sizeof Fu = %d\n", y.classinfo.init.length); // outputs 12 printf("sizeof Fubar = %d\n", z.classinfo.init.length); // outputs 16 return 0; } This supports what I had suspected, that there are extra vtable pointers introduced for each interface. If you used fat pointers (double width) for interface references you could avoid the extra space overhead. There are also potentially significant performance advantages of not using vtables to implement interfaces. Is this something which is interesting to you? Or should I let this sleeping dog lie? -- Christopher Diggins http://www.cdiggins.com http://www.heron-language.com
Apr 09 2004
parent reply "Walter" <walter digitalmars.com> writes:
"christopher diggins" <cdiggins users.sourceforge.net> wrote in message
news:c57q4g$1nep$1 digitaldaemon.com...
 This supports what I had suspected, that there are extra vtable pointers
 introduced for each interface.

That's correct.
 If you used fat pointers (double width) for
 interface references you could avoid the extra space overhead.
 There are
 also potentially significant performance advantages of not using vtables

 implement interfaces.

I don't see how.
 Is this something which is interesting to you? Or
 should I let this sleeping dog lie?

I'm curious <g>.
Apr 10 2004
parent reply "christopher diggins" <cdiggins users.sourceforge.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:c59cop$143a$1 digitaldaemon.com...
 "christopher diggins" <cdiggins users.sourceforge.net> wrote in message
 news:c57q4g$1nep$1 digitaldaemon.com...
 This supports what I had suspected, that there are extra vtable pointers
 introduced for each interface.

That's correct.
 If you used fat pointers (double width) for
 interface references you could avoid the extra space overhead.
 There are
 also potentially significant performance advantages of not using vtables

 implement interfaces.

I don't see how.
 Is this something which is interesting to you? Or
 should I let this sleeping dog lie?

I'm curious <g>.

Then now that I have piqued your interest, the technique is to use a double width pointer when referring to an object by reference. One part points to the object while the other points to a function table representing the functions of the interface. I wrote a C++ language extension to demonstrate the technique and have made it freely available at http://www.heron-language.com/heronfront.html . Let me know if you have any questions. Christopher Diggins http://www.cdiggins.com http://www.heron-language.com
Apr 10 2004
parent reply "Walter" <walter digitalmars.com> writes:
I just don't see where the performance difference is coming from. Correct me
if I'm wrong, but Heron moves the vptr from the class object to the class
reference. How does that make it faster?

Consider also that in D, a reference to an interface is really just a
pointer to a vptr.
Apr 15 2004
next sibling parent reply "christopher diggins" <cdiggins users.sourceforge.net> writes:
When using the object directly (referring to it by its concrete type) the
vtable is not needed because the functions aren't virtual. Also when
referring to an object by the interface once the first call to the object is
dispatched using a virtual table, calls within that function to other
members of the interface shouldn't be dispatched using the vtable. Doing so
would be inefficient and wrong. Am I making sense?

Btw: I am working on a significantly simplified version of HeronFront that
integrates smoother with standard C++ and requires less use of a
pre-processor. I will announce it on this newsgroup when it is available.

-- 
Christopher Diggins
http://www.cdiggins.com
http://www.heron-language.com


"Walter" <walter digitalmars.com> wrote in message
news:c5mhta$12t$1 digitaldaemon.com...
 I just don't see where the performance difference is coming from. Correct

 if I'm wrong, but Heron moves the vptr from the class object to the class
 reference. How does that make it faster?

 Consider also that in D, a reference to an interface is really just a
 pointer to a vptr.

Apr 15 2004
parent reply Ben Hinkle <bhinkle4 juno.com> writes:
[snip] 
Also when
referring to an object by the interface once the first call to the object is
dispatched using a virtual table, calls within that function to other
members of the interface shouldn't be dispatched using the vtable. 

Hmm. Does Heron allow a subclass to call a superclass implementation? If so then how are the function calls in the superclass made? If they are direct then they would not dispatch to the subclass methods, which seems like a bug. The only way out of this problem that I can see is that each method has two implementations: one with vtable dispatching to be used when called by the syntax super.foo() and another with direct function calls to be used elsewhere. Methods that aren't overridden get the dispatching version. Am I understanding this correctly? It seems like any C++ or D compiler could make such a time/space tradeoff during code generation - much like inlining functions is a time/space tradeoff.
Apr 15 2004
parent reply "christopher diggins" <cdiggins users.sourceforge.net> writes:
"Ben Hinkle" <bhinkle4 juno.com> wrote in message
news:beiu7052nddt3gomhqbno7coqnphk7trma 4ax.com...
 [snip]
Also when
referring to an object by the interface once the first call to the object


dispatched using a virtual table, calls within that function to other
members of the interface shouldn't be dispatched using the vtable.

Hmm. Does Heron allow a subclass to call a superclass implementation?

I wasn't discussing Heron. Heron doesn't allow class inheritance.
 If so then how are the function calls in the superclass made? If they
 are direct then they would not dispatch to the subclass methods, which
 seems like a bug. The only way out of this problem that I can see is
 that each method has two implementations: one with vtable dispatching
 to be used when called by the syntax super.foo() and another with
 direct function calls to be used elsewhere. Methods that aren't
 overridden get the dispatching version.

 Am I understanding this correctly? It seems like any C++ or D compiler
 could make such a time/space tradeoff during code generation - much
 like inlining functions is a time/space tradeoff.

I think you got off track somewhere. The issue is that interfaces implemented as ABC's are inherently less efficient (because of the wrognful and unnecessary virtualization of functions) than when implemented alternatively such as demonstrated by the HeronFront project at http://www.heron-language.com/heronfront.html . -- Christopher Diggins http://www.cdiggins.com http://www.heron-language.com
Apr 15 2004
parent Ilya Minkov <minkov cs.tum.edu> writes:
christopher diggins schrieb:

 I think you got off track somewhere. The issue is that interfaces
 implemented as ABC's are inherently less efficient (because of the wrognful
 and unnecessary virtualization of functions) than when implemented
 alternatively such as demonstrated by the HeronFront project at
 http://www.heron-language.com/heronfront.html .

But then again, class A inherits from an interface I, which declares a() and b(). Class B inherits from a class A and implements the interface. Class B overrides an implementation of one of the functions a() from an interface I, but leaves b() untouched. If the b() calls a() in B, the class behaves uncoherently. This is not uncommon in C++, so in D principal decision was met to make everything virtual in classes. There are a few technical solutions to that - either such calls have to be dispatched virtually, or they can be made direct, but then each function has to be generated anew for each descendant class even if it was not overriden. These 2 make sense in different situations. The first is good for development, and for large modular systems which makes it "linkable". The second was implemented in Sather compiler, and is good for whole-program compilation - it allows to use agressive strategies to eiminate all unused code as well as agressive inlining. D can princpally support both startegies - and when the popularity of D reaches a certain point, i'm sure agressive whole-program compilers will appear. Currently, it's non-agressive C++-like only, and that for a reason. Nontheless, even in such cases D can principally cut it better than C++. -eye
Apr 16 2004
prev sibling parent reply "christopher diggins" <cdiggins users.sourceforge.net> writes:
Hi Walter,

Here is a sample implementation of a struct FuBar implementing an interface
InterfaceFuBar which contains two functions: void Fu() and void Bar(), I'll
let you do your own poking and prodding at the example and I welcome any
feedback on the code itself as I am somewhat rusty at C++. Let me know if
you require commenting of the code etc.

#include <iostream>
template<typename SELF> struct ITABLE_InterfaceFuBar {
  void(SELF::*Fu)();
  void(SELF::*Bar)();
};
struct InterfaceFuBar {
  struct DUMMY_InterfaceFuBar {
    void Fu() { };
    void Bar() { };
  };
  struct DUMMY_ITABLE_InterfaceFuBar : public
ITABLE_InterfaceFuBar<DUMMY_InterfaceFuBar>  {  };
  DUMMY_InterfaceFuBar* mpObject;
  DUMMY_ITABLE_InterfaceFuBar* mpTable;
  InterfaceFuBar(void* pObject = NULL, void* pTable = NULL) {
    mpObject = (DUMMY_InterfaceFuBar*)pObject;
    mpTable = (DUMMY_ITABLE_InterfaceFuBar*)pTable;
  };
  void Fu() { (mpObject->*(mpTable->Fu))(); };
  void Bar() { (mpObject->*(mpTable->Bar))(); };
};
template<typename I, typename M> struct Implementor {
  operator I() { return I(NULL, NULL); };
};
template<typename M> struct Implementor<InterfaceFuBar, M> {
  operator InterfaceFuBar() {
    static ITABLE_InterfaceFuBar<M> tmp = { M::Fu, M::Bar };
    return InterfaceFuBar(this, (void*)&tmp);
  };
};
struct FuBar : public Implementor<InterfaceFuBar, FuBar> {
  void Fu() { std::cout << "fu" << std::endl; };
  void Bar() { std::cout << "bar" << std::endl; };
};
int main() {
  FuBar f;
  InterfaceFuBar i = f;
  i.Fu();
  std::cin.get();
  return 0;
}

-- 
Christopher Diggins
http://www.cdiggins.com
http://www.heron-language.com
Apr 15 2004
parent reply "christopher diggins" <cdiggins users.sourceforge.net> writes:
"christopher diggins" <cdiggins users.sourceforge.net> wrote in message
news:c5nk6s$1ljs$1 digitaldaemon.com...
 Hi Walter,

 Here is a sample implementation of a struct FuBar implementing an

 InterfaceFuBar which contains two functions: void Fu() and void Bar(),

 let you do your own poking and prodding at the example and I welcome any
 feedback on the code itself as I am somewhat rusty at C++. Let me know if
 you require commenting of the code etc.

So I improved on the version by removing the requirement of inheritance required on the implementing class. Just to reiterate what the heck is going on here, this is an example high performance implementation of interfaces (as they are defined in the Java specification anyway, see: http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc6. tml#invokeinterface ) #include<iostream> using namespace std; int naff = 0; struct IFuBar { // member struct for typecasting object struct DUMMY_IFuBar { void Fu() { }; void Bar() { }; }; // ITable type for this interface template<typename SELF> struct ITABLE_IFuBar { void(SELF::*Fu)(); void(SELF::*Bar)(); }; // member struct for typecasting ITable struct DUMMY_ITABLE_IFuBar : public ITABLE_IFuBar<DUMMY_IFuBar> { // empty }; // member fields DUMMY_IFuBar* mpObject; DUMMY_ITABLE_IFuBar* mpTable; // member functions // default ctor IFuBar() { Assign(NULL, NULL); } // assignment ctor template<typename T> IFuBar(T& o) { Assign(&o, GetStaticITable<T>()); } // copy ctor template<> IFuBar(IFuBar& i) { Assign(i.mpObject, i.mpTable); } // assignment from an arbitrary object that implements the interface functiosn template<typename T> IFuBar& operator=(T& o) { Assign(&o, GetStaticITable<T>()); return *this; } // copy assignment template<> IFuBar& operator=(IFuBar& o) { Assign(o.mpObject, o.mpTable); return *this; } // assignment implementation void Assign(void* pObject, void* pTable) { mpObject = (DUMMY_IFuBar*)pObject; mpTable = (DUMMY_ITABLE_IFuBar*)pTable;; } // create static ITable for given object type template<typename T> ITABLE_IFuBar<T>* GetStaticITable() { static ITABLE_IFuBar<T> itable = { T::Fu, T::Bar }; return &itable; } // interface functions void Fu() { (mpObject->*(mpTable->Fu))(); } void Bar() { (mpObject->*(mpTable->Bar))(); } }; struct FuBar { void Fu() { naff = 0; }; void Bar() { naff = 1; }; }; struct BarFu { void Fu() { naff = 2; }; void Bar() { naff = 3; }; }; int main() { FuBar f; BarFu b; IFuBar x; x = f; x.Fu(); cout << naff << endl; x.Bar(); cout << naff << endl; IFuBar y = b; x = y; // this line is crucial, it demonstrate that IFuBar does not need the type of the object to work x.Fu(); cout << naff << endl; x.Bar(); cout << naff << endl; cin.get(); return 0; }
Apr 16 2004
parent reply "Walter" <walter digitalmars.com> writes:
It is still using pointers to functions, so I don't see where the speed up
is. BTW, D implements interface dispatch much more efficiently than Java
does (it's two machine instructions), so is it possible you are comparing
the speedup of Heron with Java?
Apr 18 2004
parent reply "christopher diggins" <cdiggins users.sourceforge.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:c5uvgd$d6j$1 digitaldaemon.com...
 It is still using pointers to functions, so I don't see where the speed up
 is. BTW, D implements interface dispatch much more efficiently than Java
 does (it's two machine instructions), so is it possible you are comparing
 the speedup of Heron with Java?

I apologize, I am doing a bad job of explaining myself. I will try again. HeronFront generates interface reference objects (in C++) which are compatable with any object that implements the set of function signatures that make up the interface. This is done without requiring the object to do anything special (like making its functions virtual). So the speed up is within the objects referenced by HeronFront interface objects, compared with objects who inherit from an ABC and make all its functions virtual. There is no significant speedup between the dynamic dispatch mechanisms themselves. I have a small page and some sample code at http://www.heron-language.com/cpp-iop-example.html . Am I making more sense? -- Christopher Diggins http://www.cdiggins.com http://www.heron-language.com
Apr 19 2004
parent "Walter" <walter digitalmars.com> writes:
"christopher diggins" <cdiggins users.sourceforge.net> wrote in message
news:c6175v$1821$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:c5uvgd$d6j$1 digitaldaemon.com...
 It is still using pointers to functions, so I don't see where the speed


 is. BTW, D implements interface dispatch much more efficiently than Java
 does (it's two machine instructions), so is it possible you are


 the speedup of Heron with Java?

I apologize, I am doing a bad job of explaining myself. I will try again. HeronFront generates interface reference objects (in C++) which are compatable with any object that implements the set of function signatures that make up the interface. This is done without requiring the object to

 anything special (like making its functions virtual). So the speed up is
 within the objects referenced by HeronFront interface objects, compared

 objects who inherit from an ABC and make all its functions virtual. There

 no significant speedup between the dynamic dispatch mechanisms themselves.

 have a small page and some sample code at
 http://www.heron-language.com/cpp-iop-example.html .

 Am I making more sense?

ok, thanks for the reference.
Apr 24 2004