www.digitalmars.com         C & C++   DMDScript  

D - vtable

reply "Pavel Minayev" <evilone omen.ru> writes:
I wonder if I can rely on the order of methods in vtable
being the same as order of their declaration?

    class Something
    {
        void qwerty();
        void asdf();
    }
    Something thing;
    ...
    thing.classinfo.vtbl[thing.classinfo.vtbl.length - 1]; // asdf()?
    thing.classinfo.vtbl[thing.classinfo.vtbl.length - 2]; // qwerty()?

It seems to work with DMD, but is it portable?
Jan 18 2002
next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
Also, does the same apply to interfaces (it should, IMO, since
interfaces sometimes just ought to have fixed, predefined
order of methods - if used with COM, for example....)
Jan 18 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a29jef$1d1a$1 digitaldaemon.com...
 Also, does the same apply to interfaces (it should, IMO, since
 interfaces sometimes just ought to have fixed, predefined
 order of methods - if used with COM, for example....)

I doubt the order will be anything but declaration order. (COM won't work with interfaces, for some obscure technical reasons. I found another way to do it.)
Jan 18 2002
next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a29vu9$2ppj$1 digitaldaemon.com...

 I doubt the order will be anything but declaration order.

In _both_ cases (the first would be better!). I'm still searching for the solution of method pointers - well you've probably guessed =) - so now it seems I've found it. BTW is the ClassInfo stuff implementation-dependent or it is supposed to be strictly defined? In other words, can I rely on the fact that on any platform ClassInfo contains void*[] vtbl?
Jan 18 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2a4os$2sr5$1 digitaldaemon.com...

 In _both_ cases (the first would be better!).

Sorry forgot to put the ? at the end =) So, in both cases?
Jan 18 2002
parent "Walter" <walter digitalmars.com> writes:
Yes, in both cases it is true. And yes, I intend for the ClassInfo to be
cast in concrete, however, new members may get appended.

"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2a5cs$2t7r$1 digitaldaemon.com...
 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a2a4os$2sr5$1 digitaldaemon.com...

 In _both_ cases (the first would be better!).

Sorry forgot to put the ? at the end =) So, in both cases?

Jan 18 2002
prev sibling parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a29vu9$2ppj$1 digitaldaemon.com...
 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a29jef$1d1a$1 digitaldaemon.com...
 Also, does the same apply to interfaces (it should, IMO, since
 interfaces sometimes just ought to have fixed, predefined
 order of methods - if used with COM, for example....)

I doubt the order will be anything but declaration order. (COM won't work with interfaces, for some obscure technical reasons. I

 another way to do it.)

Yes, I meant to ask that? Is it possible to work with / write COM components in D? How does it work? You would think interfaces would be perfectly suited to COM?
Jan 18 2002
next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a2a5gd$2th1$1 digitaldaemon.com...

 Yes, I meant to ask that? Is it possible to work with / write COM

 in D?  How does it work? You would think interfaces would be perfectly
 suited
 to COM?

Other than the inability to produce DLLs (or am I wrong?), I don't really see any problems in writing a COM component. Interfaces won't suite, as Walter has just told us =), but you can always use structures. Function pointers are there as well, so what's the problem?
Jan 18 2002
parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2a5on$2tj1$1 digitaldaemon.com...
 "OddesE" <OddesE_XYZ hotmail.com> wrote in message
 news:a2a5gd$2th1$1 digitaldaemon.com...

 Yes, I meant to ask that? Is it possible to work with / write COM

 in D?  How does it work? You would think interfaces would be perfectly
 suited
 to COM?

Other than the inability to produce DLLs (or am I wrong?), I don't really see any problems in writing a COM component. Interfaces won't suite, as Walter has just told us =), but you can always use structures. Function pointers are there as well, so what's the problem?

No problem, just hadn't thought of that. However, since COM interfaces: have exactly the same functionality as D interfaces you would expect that you would be able to use them. I am just wondering why you can't, it is not like I am not believing Walter or anything.... :) -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net __________________________________________ Remove _XYZ from my address when replying by mail
Jan 18 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a2a6jl$2u00$1 digitaldaemon.com...

 have exactly the same functionality as D interfaces you would expect that
 you would be able to use them. I am just wondering why you can't, it is
 not like I am not believing Walter or anything....   :)

Maybe because they store ClassInfo? // object.d struct Interface { ClassInfo classinfo; void *[] vtbl; } Just a thought...
Jan 18 2002
next sibling parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2a9r5$3077$1 digitaldaemon.com...
 "OddesE" <OddesE_XYZ hotmail.com> wrote in message
 news:a2a6jl$2u00$1 digitaldaemon.com...

 have exactly the same functionality as D interfaces you would expect


 you would be able to use them. I am just wondering why you can't, it is
 not like I am not believing Walter or anything....   :)

Maybe because they store ClassInfo? // object.d struct Interface { ClassInfo classinfo; void *[] vtbl; } Just a thought...

Seems logical...But maybe it could be tweaked around to be compatible with COM? That would be more natural than using structs with tables of function pointers IMHO... -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net __________________________________________ Remove _XYZ from my address when replying by mail
Jan 18 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a2acsb$mj$1 digitaldaemon.com...

 Seems logical...But maybe it could be tweaked around to be compatible with
 COM?
 That would be more natural than using structs with tables of function
 pointers IMHO...

Some special language construct? BTW also because vtbl is a dynamic array, so it's practically a struct { pointer, int }...
Jan 18 2002
prev sibling parent "Juan Carlos Arevalo Baeza" <jcab roningames.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2a9r5$3077$1 digitaldaemon.com...
 "OddesE" <OddesE_XYZ hotmail.com> wrote in message
 news:a2a6jl$2u00$1 digitaldaemon.com...

 have exactly the same functionality as D interfaces you would expect


 you would be able to use them. I am just wondering why you can't, it is
 not like I am not believing Walter or anything....   :)

Maybe because they store ClassInfo? // object.d struct Interface { ClassInfo classinfo; void *[] vtbl; } Just a thought...

ClassInfo pointers can (and should? I don't know the internals of D that well... but C++ does it that way) be stored in the vtbl (as the [-1] pointer) and stay COM-compatible. Salutaciones, JCAB
Jan 18 2002
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a2a5gd$2th1$1 digitaldaemon.com...
 Yes, I meant to ask that? Is it possible to work with / write COM

 in D?  How does it work? You would think interfaces would be perfectly
 suited
 to COM?

COM requires: 1) the first entry in an object is a vptr 2) the layout of the vtbl[] is exactly like C++ single inheritance 3) stdcall calling conventions 4) AddRef() and Release() memory management. D Objects fail (2), (3), (4) [(2) because the first entry in the vtbl[] is the ClassInfo followed by the Object functions]. D Interfaces fail (1), (3), (4). The solution is to recognize a special root object (strangely enough called "IUnknown" <g>). Deriving from this, instead of from Object, means you wind up with a COM style vtbl[], and it also sets the function calling conventions to stdcall. This has some effects like you can't do a .classinfo on a COM object (no rtti). COM objects are also reference counted, and are not on the garbage collected heap. It sounds wartier than it actually is. In my experiments, it's much more natural to write COM code in D than it is in C++, despite COM being designed for C++. Portability of this kludge is not an issue, since COM is only for Windows anyway. It will be possible to write DLLs in D, I just haven't written the necessary library support for it yet.
Jan 18 2002
next sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a2ad4l$128$1 digitaldaemon.com...

 COM requires:
 1) the first entry in an object is a vptr
 2) the layout of the vtbl[] is exactly like C++ single inheritance
 3) stdcall calling conventions
 4) AddRef() and Release() memory management.

 D Interfaces fail (1), (3), (4).

Why (3)? Isn't extern(Windows) applicable to methods? I remember you used extern(C) for OutBuffer.printf() (and so did I for Stream.printf(), then =)), and it worked...
 The solution is to recognize a special root object (strangely enough

 "IUnknown" <g>). Deriving from this, instead of from Object, means you

 up with a COM style vtbl[], and it also sets the function calling
 conventions to stdcall. This has some effects like you can't do a

 on a COM object (no rtti). COM objects are also reference counted, and are
 not on the garbage collected heap.

It's pretty okay.
 It will be possible to write DLLs in D, I just haven't written the

 library support for it yet.

...which is pretty possible to do ourselves, right? Isn't is as simple as providing our own version of dmain2.d?
Jan 18 2002
parent "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2aes3$24o$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a2ad4l$128$1 digitaldaemon.com...

 COM requires:
 1) the first entry in an object is a vptr
 2) the layout of the vtbl[] is exactly like C++ single inheritance
 3) stdcall calling conventions
 4) AddRef() and Release() memory management.

 D Interfaces fail (1), (3), (4).

Why (3)? Isn't extern(Windows) applicable to methods? I remember you used extern(C) for OutBuffer.printf() (and so did I for Stream.printf(), then =)), and it worked...

Yes, the extern works with methods. It just isn't the default.
 The solution is to recognize a special root object (strangely enough

 "IUnknown" <g>). Deriving from this, instead of from Object, means you

 up with a COM style vtbl[], and it also sets the function calling
 conventions to stdcall. This has some effects like you can't do a

 on a COM object (no rtti). COM objects are also reference counted, and


 not on the garbage collected heap.

It's pretty okay.
 It will be possible to write DLLs in D, I just haven't written the

 library support for it yet.

...which is pretty possible to do ourselves, right? Isn't is as simple as providing our own version of dmain2.d?

Yeah, that's about it.
Jan 18 2002
prev sibling parent reply Russell Borogove <kaleja estarcion.com> writes:
Walter wrote:

 The solution is to recognize a special root object (strangely enough called
 "IUnknown" <g>). [details omitted]
 
 It sounds wartier than it actually is.

Actually, from the outside it sounds pretty elegant, even if it's warty on the inside. -RB
Jan 18 2002
parent "OddesE" <OddesE_XYZ hotmail.com> writes:
"Russell Borogove" <kaleja estarcion.com> wrote in message
news:3C48E52C.10801 estarcion.com...
 Walter wrote:

 The solution is to recognize a special root object (strangely enough


 "IUnknown" <g>). [details omitted]

 It sounds wartier than it actually is.

Actually, from the outside it sounds pretty elegant, even if it's warty on the inside. -RB

Indeed, it does sound pretty elegant! Is the IUnknown root object part of the standard D libraries? Très Cool! I was delving into COM just before I learned of D, and I like both of them a lot, but I had I concern I couldn't mix coding with the two, so that would have been a shame. It is great to hear that not only is it supported, but that it is actually cleaner to do than in C++! -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net __________________________________________ Remove _XYZ from my address when replying by mail
Jan 19 2002
prev sibling parent reply Roland <rv ronetech.com> writes:
Pavel Minayev a écrit :

 I wonder if I can rely on the order of methods in vtable
 being the same as order of their declaration?

     class Something
     {
         void qwerty();
         void asdf();
     }
     Something thing;
     ...
     thing.classinfo.vtbl[thing.classinfo.vtbl.length - 1]; // asdf()?
     thing.classinfo.vtbl[thing.classinfo.vtbl.length - 2]; // qwerty()?

 It seems to work with DMD, but is it portable?

At last you got it (vtbl) ? For portability and readeability it would be nice something like thing.classinfo.vtbl.qwerty (why do i always have ideas for _more_ work for walter and never for _less_ ?) Roland
Jan 18 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Roland" <rv ronetech.com> wrote in message
news:3C486B82.F2E11B62 ronetech.com...

 At last you got it (vtbl) ?

? It always was there!
 For portability and readeability it would be nice something like
     thing.classinfo.vtbl.qwerty

Why if you can write "thing.qwerty" ? =) One great thing would be an associative-array vtable (and one for properties as well, storing their offsets from "this"): thing.classinfo.method["qwerty"]; thing.classinfo.property["asdf"];
Jan 18 2002
parent reply roland <nancyetroland free.fr> writes:
Pavel Minayev a écrit :

 "Roland" <rv ronetech.com> wrote in message
 news:3C486B82.F2E11B62 ronetech.com...

 At last you got it (vtbl) ?

? It always was there!

? don't see in the spec. vtbl propertie is the virtual table right ? For a little while, I suspect you to make some kind of pointer to methode replacement writing in the vtbl. good idea..
 For portability and readeability it would be nice something like
     thing.classinfo.vtbl.qwerty

Why if you can write "thing.qwerty" ? =)

I agree, can you now ? If yes, i missed the conclusion of a previous discussion. Roland
Jan 18 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"roland" <nancyetroland free.fr> wrote in message
news:3C489394.B3380956 free.fr...

 ? don't see in the spec.

The best spec is Phobos source, see the files object.d and cast.d, how it is used here. Also new.cpp contains code that shows how to create an instance of object by its ClassInfo, bypassing operator new; unfortunately, constructor is not called...
 vtbl propertie is the virtual table right ?

Right. Here's the whole thingie: class ClassInfo : Object { byte[] init; // class static initializer char[] name; // class name void *[] vtbl; // virtual function pointer table Interface[] interfaces; ClassInfo base; void *destructor; void (*_invariant)(Object); } Quite interesting...
  For a little while, I suspect you to make some kind of pointer to
 methode replacement writing in the vtbl.
 good idea..

Yes. If order of methods in vtbl is as they're declared, we can always get the address of last method, one before the last, etc. So: class MyForm { this() { // offset from end of vtable is used as function pointer cmdOk.OnClick = Handler.cmdOk_Click; cmdCancel.OnClick = Handler.cmdCancel_Click; } // various methods ... void cmdOk_Click() { ... } void cmdCancel_Click() { ... } // reversed order (count from end) enum Handler { cmdCancel_Click, cmdOk_Click } }
 Why if you can write "thing.qwerty" ? =)

I agree, can you now ?

You mean to get an address of method? No, I asked Walter about that already: "For an answer right now, it'll be "no". Doesn't mean it will always be that way, doesn't mean that method pointers are a bad idea, I just am buried with work and I can't address it now." Funny, you can write something like &qwerty, which gets parsed fine but causes the compiler to crash later =)
Jan 18 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2a56s$2t6t$1 digitaldaemon.com...

 You mean to get an address of method? No, I asked Walter about that
 already:

     "For an answer right now, it'll be "no". Doesn't mean it will always
     be that way, doesn't mean that method pointers are a bad idea, I just
     am buried with work and I can't address it now."

An idea came to my mind... what if compiler generates an enum for each class, listing all methods introduced in this class (not overridden!), like this: class Foo { // this is what we type void bar(); int baz(); // and this is what the compiler adds implicitly enum vtable { bar, baz } } Now we have relative positions of methods in vtable. Using classinfo.vtbl and classinfo.base.vtbl, these can easily be converted to pointers: bar_ptr = classinfo.vtbl[classinfo.base.vtbl.length + vtable.bar]; What's also great is that no syntax additions or changes are required, code that would be used to implement this solution is minimal... still all benefits of method pointers are there. What do you think about this, Walter?
Jan 18 2002
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2aaa5$30k9$1 digitaldaemon.com...
 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a2a56s$2t6t$1 digitaldaemon.com...

 You mean to get an address of method? No, I asked Walter about that
 already:

     "For an answer right now, it'll be "no". Doesn't mean it will always
     be that way, doesn't mean that method pointers are a bad idea, I


     am buried with work and I can't address it now."

An idea came to my mind... what if compiler generates an enum for each class, listing all methods introduced in this class (not overridden!), like this: class Foo { // this is what we type void bar(); int baz(); // and this is what the compiler adds implicitly enum vtable { bar, baz } } Now we have relative positions of methods in vtable. Using classinfo.vtbl and classinfo.base.vtbl, these can easily be converted to pointers: bar_ptr = classinfo.vtbl[classinfo.base.vtbl.length + vtable.bar]; What's also great is that no syntax additions or changes are required, code that would be used to implement this solution is minimal... still all benefits of method pointers are there. What do you think about this, Walter?

It's a great idea, but doesn't work if functions are overloaded. -Walter
Jan 18 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a2ad7v$12e$1 digitaldaemon.com...

 It's a great idea, but doesn't work if functions are overloaded. -Walter

Overloaded ones could be skipped: enum vtable { foo, // foo bar = foo + 2, // bar, // bar, baz = bar + 3, }
Jan 18 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
Or even:

    enum vtable
    {
        foo,
        // bar,
        // bar,
        // bar,
        baz = foo + 4
    }

So no pointers for overloaded functions.
Who needs them anyhow? =)
Jan 18 2002
parent reply "Patrick Down" <pdown austin.rr.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2aik2$4l7$1 digitaldaemon.com...
 Or even:

     enum vtable
     {
         foo,
         // bar,
         // bar,
         // bar,
         baz = foo + 4
     }

 So no pointers for overloaded functions.
 Who needs them anyhow? =)

I suppose this would be rather iky? enum vtable { foo_v, bar_i, bar_icda, bar_f, baz } // i = int, c = char, da = dynamic array, f = float or better yet thing.classinfo.method{"int bar(int)"]; thing.classinfo.method{"int bar(char[])"]; Walter, are functions in D overloadable on return type?
Jan 18 2002
next sibling parent "Pavel Minayev" <evilone omen.ru> writes:
"Patrick Down" <pdown austin.rr.com> wrote in message
news:a2b3lv$f6a$1 digitaldaemon.com...

 I suppose this would be rather iky?

 enum vtable
 {
     foo_v,
     bar_i,
     bar_icda,
     bar_f,
     baz
 } // i = int, c = char, da = dynamic array, f = float

Yep, because imagine a user trying to build the name of the function out of its arguments (because he doesn't see that compiler-generated enum). I must say that, having worked with Delphi for a long time, I don't remember any program that took a function pointer to an overloaded function. This is something that can be sacrificed, IMO.
 thing.classinfo.method{"int bar(int)"];
 thing.classinfo.method{"int bar(char[])"];

This moves most of the code to run-time (since with enum we already have positions in vtable, and here it has to find a key in an associative array).
Jan 19 2002
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Patrick Down" <pdown austin.rr.com> wrote in message
news:a2b3lv$f6a$1 digitaldaemon.com...
 Walter, are functions in D overloadable on return type?

No, for the same reasons as in C++. It prevents bottom up semantic analysis.
Jan 20 2002
prev sibling parent reply "Pavel Minayev" <evilone omen.ru> writes:
Okay, so it turned out to be not that simple...

Since extern(D) - the default - doesn't specify order of
arguments strictly, it cannot be used in low-level, so
methods we want to get pointers to have to be extern(C).
The problem is, such methods don't reside in the vtable -
they are called directly! So, once again, the only way
to get a pointer to it is some special operator, or
something...
Jan 19 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
I should have thought twice before posting... =)

Now, I came to the working solution, which seems perferctly
portable. The idea is to define a base class for all classes
that want pointers to their functions (most frequently it's
class itself who uses pointers to its methods anyhow), and
let it contain a dummy entry in the vtable - just an empty
function - which then gets substituted by whatever pointer
we have. So:

    class Component: Object
    {
        // should be the very first
        void _event_callback(void* ptr) { }
    }
    Component obj;
    ...
    // put pointer to our callback method into the vtable...
    obj.classinfo.vtable[Object.classinfo.vtable.length] =
our_function_pointer;
    // ...and call it!
    obj._event_callback(pointer_to_some_data);

Unfortunately D doesn't allow class.classinfo (only object.classinfo) -
btw a feature request, Walter! =) - but nothing stops us from creating
a temporary Object in static constructor and getting it's vtable.length...

So if we get the method-list enumeration, method pointers can be
considered there.
Jan 19 2002
parent "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a2bp3d$vrt$1 digitaldaemon.com...
 Unfortunately D doesn't allow class.classinfo (only object.classinfo) -
 btw a feature request, Walter! =)

I thought that worked. If not, it's a bug. -Walter
Jan 20 2002