D - [BUG] casting Interface to class-instance generates bogus code
- Kris (11/11) Apr 04 2004 I have a concrete-class that implements a generic interface. On occasion...
- Kris (11/11) Apr 04 2004 On a hunch, I thought I'd try the old (void *) trick.
- Ant (4/8) Apr 04 2004 great. I had the same problem before and my work
- Walter (22/33) Apr 05 2004 The problem here is that all an interface is, when implemented, is a poi...
- Kris (9/16) Apr 05 2004 Thank-you Walter. I truly appreciate your help on this.
-
Walter
(4/8)
Apr 05 2004
It's the long term solution
. The reason for the null result is to mi... - Kris (11/19) Apr 05 2004 Whoops -- I meant to add why I feel this should not be the accepted
- Kris (35/39) Apr 05 2004 Please forgive my gratuitous overuse of this NG ...
- Walter (8/48) Apr 05 2004 I think this idea of yours will work fine. A hidden method cannot be add...
- Hauke Duden (7/10) Apr 05 2004 "No way", as in "impossible", or in "no way" as in "not for 1.0"? ;)
- Walter (4/13) Apr 05 2004 pointer
- C (9/26) Apr 06 2004 Forgive my ignorance, but why would it be incompatible ?
- Hauke Duden (17/21) Apr 06 2004 I guess what Walter means is that then it would be very hard to cast a
- Ben Hinkle (8/11) Apr 06 2004 pointer
- Russ Lewis (23/66) Apr 06 2004 As Kris notes in a reply elsewhere, this is problematic because then the...
I have a concrete-class that implements a generic interface. On occasion, said interface needs to be upcast to the concrete-class to access specialized functionality. Check out the cast(SocketConduit) code below ... it explicitly sets the lValue to zero. Good Grief ... 112: char[] getRemoteAddress (IConduit conduit) 00403290 enter 0Ch,0 00403294 mov dword ptr [ebp-0Ch],eax 113: { 114: SocketConduit socket = cast(SocketConduit) conduit; 00403297 xor eax,eax 00403299 mov dword ptr [socket],eax
Apr 04 2004
On a hunch, I thought I'd try the old (void *) trick. As you can see below, it actually persuaded the compiler into doing the right thing. Oh well; onto the next showstopper. 112: char[] getRemoteAddress (IConduit conduit) 00403290 enter 0Ch,0 00403294 mov dword ptr [ebp-0Ch],eax 113: { 114: SocketConduit socket = cast(SocketConduit) cast(void *) conduit; 00403297 mov eax,dword ptr [conduit] 0040329A mov dword ptr [socket],eax
Apr 04 2004
On Sun, 04 Apr 2004 19:25:18 -0800, Kris wrote:On a hunch, I thought I'd try the old (void *) trick. 114: SocketConduit socket = cast(SocketConduit) cast(void *) conduit;great. I had the same problem before and my work around was... so complex that I even don't remember. Ant
Apr 04 2004
Oops; I'm afraid I jumped the gun on that one. The (void *) cast drops some of the vTable offsets (or something), so it end's up calling the wrong place. I'm not sure if that's better or worse than before :-) I was just going through the code to see if I could avoid the interface altogether, and I'm afraid that would make the whole system specific to SocketConduit only. Hence that is simply not an option. If you can recall what you did to resolve your issue? I'd really appreciate any help Ant. Cheers, - KrisAnt wrote: great. I had the same problem before and my work around was... so complex that I even don't remember. Ant
Apr 04 2004
On Sun, 04 Apr 2004 19:48:27 -0800, Kris wrote:Oops; I'm afraid I jumped the gun on that one. The (void *) cast drops some of the vTable offsets (or something), so it end's up calling the wrong place. I'm not sure if that's better or worse than before :-) I was just going through the code to see if I could avoid the interface altogether, and I'm afraid that would make the whole system specific to SocketConduit only. Hence that is simply not an option. If you can recall what you did to resolve your issue? I'd really appreciate any help Ant. Cheers, - KrisSorry, I don't think I can help, I really don't remember but I think I redesign something and I'm avoiding it since. I believe this is covered on Burton Radons interface and inheritance bug report let's hope Walter is looking at that. Ant
Apr 04 2004
The problem here is that all an interface is, when implemented, is a pointer to a vtbl[]. There's no way the runtime can tell where it came from, so there is no way to upcast it. The way to deal with this is to add a member function to the interface that is equivalent to the 'ClassFactory' function in COM programming. Then, in the implementation of that function, which does know the object type enclosing the interface, the cast can be done. interface IConduit { SocketConduit isSocketConduit(); } class SocketConduit : IConduit { SocketConduit isSocketConduit() { return this; } } char[] getRemoteAddress(IConduit conduit) { SocketConduit socket = conduit.isSocketConduit(); } "Kris" <someidiot earthlink.dot.dot.dot.net> wrote in message news:c4qi35$24f8$1 digitaldaemon.com...I have a concrete-class that implements a generic interface. On occasion, said interface needs to be upcast to the concrete-class to access specialized functionality. Check out the cast(SocketConduit) code below...it explicitly sets the lValue to zero. Good Grief ... 112: char[] getRemoteAddress (IConduit conduit) 00403290 enter 0Ch,0 00403294 mov dword ptr [ebp-0Ch],eax 113: { 114: SocketConduit socket = cast(SocketConduit) conduit; 00403297 xor eax,eax 00403299 mov dword ptr [socket],eax
Apr 05 2004
Thank-you Walter. I truly appreciate your help on this. BTW, is this the expected long-term solution? If so (and I don't think it should be <g>) the compiler really needs to toss an error, rather than emitting grossly unjust access-violators ... - Kris "Walter" <walter digitalmars.com> wrote in message news:c4sk0f$2eon$1 digitaldaemon.com...The problem here is that all an interface is, when implemented, is apointerto a vtbl[]. There's no way the runtime can tell where it came from, so there is no way to upcast it. The way to deal with this is to add a member function to the interfacethatis equivalent to the 'ClassFactory' function in COM programming. Then, in the implementation of that function, which does know the object type enclosing the interface, the cast can be done.
Apr 05 2004
"Kris" <someidiot earthlink.dot.dot.dot.net> wrote in message news:c4ska9$2f70$1 digitaldaemon.com...Thank-you Walter. I truly appreciate your help on this. BTW, is this the expected long-term solution? If so (and I don't think it should be <g>) the compiler really needs to toss an error, rather than emitting grossly unjust access-violators ...It's the long term solution <g>. The reason for the null result is to mimic the behavior of dynamic_cast in C++.
Apr 05 2004
Whoops -- I meant to add why I feel this should not be the accepted procedure: The solution provided works fine to skirt the issue at hand, but the methodology requires that the base-class (or base-interface) is pre-configured to know about *all possible derivations* (subclasses). That, is simply unrealistic. - Kris "Walter" <walter digitalmars.com> wrote in message news:c4sk0f$2eon$1 digitaldaemon.com...The problem here is that all an interface is, when implemented, is apointerto a vtbl[]. There's no way the runtime can tell where it came from, so there is no way to upcast it. The way to deal with this is to add a member function to the interfacethatis equivalent to the 'ClassFactory' function in COM programming. Then, in the implementation of that function, which does know the object type enclosing the interface, the cast can be done.
Apr 05 2004
Please forgive my gratuitous overuse of this NG ... Thinking about this a little more Walter, if the base-interface were to implement just the upcast to a concrete Object, then dynamic-casting should handle it from there. For example: interface IConduit { Object toObject(); } class SocketConduit : IConduit { Object toObject() { return this; } } char[] getRemoteAddress(IConduit conduit) { SocketConduit socket = cast(SocketConduit) conduit.toObject(); } This, at least, is extensible. Though I'm torn as to whether it's the right-thing-to-do <g> Note: one might be tempted to implement this instead as: interface IConduit { Conduit toConduit(); } ...assuming there were a base-class implementation for IConduit. However, that doesn't lend itself toward a sense of 'pattern' (let alone the potential "forward reference" issues that an Interfaces is handy for resolving). If, in fact, you were to decide the suggested approach is the long-term solution, then you might consider adding a hidden toObject() declaration to each interface, and the corresponding "return this;" implementation to each of the appropriate classes. If so, toObject() could thus become a property of any Interface. Not too sure about that attitude though. "Kris" <someidiot earthlink.dot.dot.dot.net> wrote in message news:c4skns$2fu9$1 digitaldaemon.com...The solution provided works fine to skirt the issue at hand, but the methodology requires that the base-class (or base-interface) is pre-configured to know about *all possible derivations* (subclasses).That,is simply unrealistic.
Apr 05 2004
I think this idea of yours will work fine. A hidden method cannot be added, though, because then it would not work as a COM object. "Kris" <someidiot earthlink.dot.dot.dot.net> wrote in message news:c4smb9$2imr$1 digitaldaemon.com...Please forgive my gratuitous overuse of this NG ... Thinking about this a little more Walter, if the base-interface were to implement just the upcast to a concrete Object, then dynamic-castingshouldhandle it from there. For example: interface IConduit { Object toObject(); } class SocketConduit : IConduit { Object toObject() { return this; } } char[] getRemoteAddress(IConduit conduit) { SocketConduit socket = cast(SocketConduit) conduit.toObject(); } This, at least, is extensible. Though I'm torn as to whether it's the right-thing-to-do <g> Note: one might be tempted to implement this instead as: interface IConduit { Conduit toConduit(); } ...assuming there were a base-class implementation for IConduit. However, that doesn't lend itself toward a sense of 'pattern' (let alonethepotential "forward reference" issues that an Interfaces is handy for resolving). If, in fact, you were to decide the suggested approach is the long-term solution, then you might consider adding a hidden toObject() declarationtoeach interface, and the corresponding "return this;" implementation toeachof the appropriate classes. If so, toObject() could thus become a property of any Interface. Not too sure about that attitude though. "Kris" <someidiot earthlink.dot.dot.dot.net> wrote in message news:c4skns$2fu9$1 digitaldaemon.com...The solution provided works fine to skirt the issue at hand, but the methodology requires that the base-class (or base-interface) is pre-configured to know about *all possible derivations* (subclasses).That,is simply unrealistic.
Apr 05 2004
Walter wrote:The problem here is that all an interface is, when implemented, is a pointer to a vtbl[]. There's no way the runtime can tell where it came from, so there is no way to upcast it."No way", as in "impossible", or in "no way" as in "not for 1.0"? ;) Couldn't there be a virtual function "Object __getObject()" that is automatically generated for all classes? Then the cast operator could simply call this function when casting an interface to an object. Seems like the only way to have the cast operator behave consistently. Hauke
Apr 05 2004
"Hauke Duden" <H.NS.Duden gmx.net> wrote in message news:c4snu4$2kv8$1 digitaldaemon.com...Walter wrote:pointerThe problem here is that all an interface is, when implemented, is aIt could, but then it would be incompatible with COM programming.to a vtbl[]. There's no way the runtime can tell where it came from, so there is no way to upcast it."No way", as in "impossible", or in "no way" as in "not for 1.0"? ;) Couldn't there be a virtual function "Object __getObject()" that is automatically generated for all classes? Then the cast operator could simply call this function when casting an interface to an object. Seems like the only way to have the cast operator behave consistently.
Apr 05 2004
It could, but then it would be incompatible with COM programming.Forgive my ignorance, but why would it be incompatible ? C On Mon, 5 Apr 2004 16:06:30 -0700, Walter <walter digitalmars.com> wrote= :"Hauke Duden" <H.NS.Duden gmx.net> wrote in message news:c4snu4$2kv8$1 digitaldaemon.com...aWalter wrote:The problem here is that all an interface is, when implemented, is =pointer, =to a vtbl[]. There's no way the runtime can tell where it came from=sothere is no way to upcast it."No way", as in "impossible", or in "no way" as in "not for 1.0"? ;) Couldn't there be a virtual function "Object __getObject()" that is automatically generated for all classes? Then the cast operator could=mssimply call this function when casting an interface to an object. See=-- = D Newsgroup.like the only way to have the cast operator behave consistently.It could, but then it would be incompatible with COM programming.
Apr 06 2004
C wrote:I guess what Walter means is that then it would be very hard to cast a COM object into a D interface, since COM interfaces don't have a delete or toObject method by default. But the thing is, I believe this kind of problem already exists and cannot be circumvented. COM objects cannot be collected by the garbage collector, since the COM rules state that a Release call is the only way a COM object can be deleted. So you cannot explicitly delete COM objects and you cannot leave them to be collected. You HAVE to do your own memory management, i.e. you cannot treat them like other D interfaces. So, since COM and D interfaces are already incompatible I fail to see the reason why further incompatibilities should be a reason to restrict D. What this all comes down to is that you ALREADY have to be aware that you deal with a COM interface instead of a D interface and treat it differently. So you can just as well remember that toObject or delete will return null / have no effect, whatever. HaukeIt could, but then it would be incompatible with COM programming.Forgive my ignorance, but why would it be incompatible ?
Apr 06 2004
"Walter" <walter digitalmars.com> wrote in message news:c4sk0f$2eon$1 digitaldaemon.com...The problem here is that all an interface is, when implemented, is apointerto a vtbl[]. There's no way the runtime can tell where it came from, so there is no way to upcast it.I don't know the internals all that well, but at runtime the object implementing the interface knows its class, right? Isn't that how dynamic casting works? Is the problem that there exist "ClassInfo" but no "InterfaceInfo"? -Ben
Apr 06 2004
As Kris notes in a reply elsewhere, this is problematic because then the interface (and all classes which implement the interface) must know all derived classes. How about this mechanism instead, which (if it works) could easily be implemented automatically by the compiler: interface IConduit { Object getObject(); } class SocketConduit : IConduit { Object getObject() { return this; } } char[] getRemoteAddress(IConduit conduit) { SocketConduit socket = cast(SocketConduit)conduit.getObject(); } That is, every interface includes a function which will return an Object reference...then normal D casting mechanisms can upcast the Object to whatever class you think it is. IMHO, this should be the automatic behavior when you try to cast an interface to a class...the compiler should do this for you. Thoughts? Walter wrote:The problem here is that all an interface is, when implemented, is a pointer to a vtbl[]. There's no way the runtime can tell where it came from, so there is no way to upcast it. The way to deal with this is to add a member function to the interface that is equivalent to the 'ClassFactory' function in COM programming. Then, in the implementation of that function, which does know the object type enclosing the interface, the cast can be done. interface IConduit { SocketConduit isSocketConduit(); } class SocketConduit : IConduit { SocketConduit isSocketConduit() { return this; } } char[] getRemoteAddress(IConduit conduit) { SocketConduit socket = conduit.isSocketConduit(); } "Kris" <someidiot earthlink.dot.dot.dot.net> wrote in message news:c4qi35$24f8$1 digitaldaemon.com...I have a concrete-class that implements a generic interface. On occasion, said interface needs to be upcast to the concrete-class to access specialized functionality. Check out the cast(SocketConduit) code below...it explicitly sets the lValue to zero. Good Grief ... 112: char[] getRemoteAddress (IConduit conduit) 00403290 enter 0Ch,0 00403294 mov dword ptr [ebp-0Ch],eax 113: { 114: SocketConduit socket = cast(SocketConduit) conduit; 00403297 xor eax,eax 00403299 mov dword ptr [socket],eax
Apr 06 2004