www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Class info on interfaces

reply Jacob Carlborg <doob me.com> writes:
I noticed the calling "classinfo" on an interface returns the class info 
of the static type and not the dynamic type. Is that intentional? 
Perhaps because of COM and C++ interfaces?

module main;

import std.stdio;

interface Foo {}
class Bar : Foo {}

void main()
{
     Foo f = new Bar;
     writeln(f.classinfo);
}

The above program will print the static type "main.Foo" instead of the 
dynamic type "main.Bar".

-- 
/Jacob Carlborg
Aug 26 2015
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Wednesday, 26 August 2015 at 18:53:19 UTC, Jacob Carlborg 
wrote:
 Is that intentional? Perhaps because of COM and C++ interfaces?
Yes, exactly. COM and C++ things won't necessarily have a D TypeInfo available and since interfaces can be them, it can't be sure. What I do there is to just cast the interface to Object. Then you should check for null to cover those cases, then you can typeid or classinfo it.
Aug 26 2015
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/26/2015 11:59 AM, Adam D. Ruppe wrote:
 On Wednesday, 26 August 2015 at 18:53:19 UTC, Jacob Carlborg wrote:
 Is that intentional? Perhaps because of COM and C++ interfaces?
Yes, exactly. COM and C++ things won't necessarily have a D TypeInfo available and since interfaces can be them, it can't be sure. What I do there is to just cast the interface to Object. Then you should check for null to cover those cases, then you can typeid or classinfo it.
To complete, the documentation says ".classinfo applied to an interface gives the information for the interface, not the class it might be an instance of." http://dlang.org/property.html#classinfo Ali
Aug 26 2015
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2015-08-26 20:59, Adam D. Ruppe wrote:

 Yes, exactly. COM and C++ things won't necessarily have a D TypeInfo
 available and since interfaces can be them, it can't be sure.

 What I do there is to just cast the interface to Object. Then you should
 check for null to cover those cases, then you can typeid or classinfo it.
Is it possible to detect at compile time if an interface is not a native D interface? Now when I think about it, we actually have four (!) different kinds of interfaces. Native D, C++, Objective-C and COM. -- /Jacob Carlborg
Aug 27 2015
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 28 August 2015 at 06:19:55 UTC, Jacob Carlborg wrote:
 Is it possible to detect at compile time if an interface is not 
 a native D interface?
Not fully, no, but you might be able to reflect into the methods and see what kind of linkage they have. http://dlang.org/phobos/std_traits.html#functionLinkage The interface itself won't necessarily be marked extern - on the binary level, they are all the same (I think... just a pointer to a list of function pointers), but if you look at the methods you can make a reasonably good guess. However, you can't do anything with an interface that isn't in there anyway without a runtime cast, so you might want to just skip any compile time guesses and just go with the runtime check.
 Now when I think about it, we actually have four (!) different 
 kinds of interfaces. Native D, C++, Objective-C and COM.
aye, and since the interface is so simple at the binary level, it is possible to use them for other things too (I think a glib object in C is also binary compatible...); I'm sure this won't be the end of the list.
Aug 28 2015
parent Jacob Carlborg <doob me.com> writes:
On 2015-08-28 16:31, Adam D. Ruppe wrote:

 Not fully, no, but you might be able to reflect into the methods and see
 what kind of linkage they have.

 http://dlang.org/phobos/std_traits.html#functionLinkage
That might work.
 However, you can't do anything with an interface that isn't in there
 anyway without a runtime cast, so you might want to just skip any
 compile time guesses and just go with the runtime check.
Well, this would be for my serialization library. If the static type it's not a native D interface I don't have way to recreate the instance when deserializing, at least not with the default deserialization process. -- /Jacob Carlborg
Aug 28 2015
prev sibling parent reply "rumbu" <rumbu rumbu.ro> writes:
On Friday, 28 August 2015 at 06:19:55 UTC, Jacob Carlborg wrote:
 On 2015-08-26 20:59, Adam D. Ruppe wrote:

 Yes, exactly. COM and C++ things won't necessarily have a D 
 TypeInfo
 available and since interfaces can be them, it can't be sure.

 What I do there is to just cast the interface to Object. Then 
 you should
 check for null to cover those cases, then you can typeid or 
 classinfo it.
Is it possible to detect at compile time if an interface is not a native D interface? Now when I think about it, we actually have four (!) different kinds of interfaces. Native D, C++, Objective-C and COM.
I don't know about Objective-C, but: - for native D interfaces __traits(getVirtualIndex, NativeInterface.firstFunction) == 1 since the first entry in vtbl is the contained object - for C++ interfaces __traits(getVirtualIndex, CPPInterface.firstFunction) == 0 - COM interfaces: __traits(getVirtualIndex, CPPInterface.firstFunction) == 0 and inherit IUnknown At runtime, it's simple, you have the m_flags member of TypeInfo_Class (isCPPclass, isCOMclass)
Aug 28 2015
parent reply Jacob Carlborg <doob me.com> writes:
On 2015-08-28 17:41, rumbu wrote:

 I don't know about Objective-C, but:

 - for native D interfaces __traits(getVirtualIndex,
 NativeInterface.firstFunction) == 1 since the first entry in vtbl is the
 contained object
 - for C++ interfaces __traits(getVirtualIndex,
 CPPInterface.firstFunction) == 0
 - COM interfaces: __traits(getVirtualIndex, CPPInterface.firstFunction)
 == 0 and inherit IUnknown
I'm wondering how reliable that is. Might be better to check the linkage of a method in the interface as Adam suggested. -- /Jacob Carlborg
Aug 28 2015
parent reply "rumbu" <rumbu rumbu.ro> writes:
On Friday, 28 August 2015 at 19:36:37 UTC, Jacob Carlborg wrote:
 On 2015-08-28 17:41, rumbu wrote:

 I don't know about Objective-C, but:

 - for native D interfaces __traits(getVirtualIndex,
 NativeInterface.firstFunction) == 1 since the first entry in 
 vtbl is the
 contained object
 - for C++ interfaces __traits(getVirtualIndex,
 CPPInterface.firstFunction) == 0
 - COM interfaces: __traits(getVirtualIndex, 
 CPPInterface.firstFunction)
 == 0 and inherit IUnknown
I'm wondering how reliable that is. Might be better to check the linkage of a method in the interface as Adam suggested.
The linkage check it's good as long you don't have an abomination like this: extern(C++) interface CPPInterface { extern(D) void foo(); } Anyway, the problem is the availability of such function. If the interface doesn't contain any function, there is no way to detect the type, except for COM Interfaces which are clearly implementing IUnknown. But deriving a new interface and defining a sentinel function, it works: import std.stdio; import std.traits; import core.sys.windows.com; interface NativeInterface {} interface COMInterface : IUnknown {} extern(C++) interface CPPInterface {} enum InterfaceKind { native, windows, cpp } template interfaceKind(I) if (is(I == interface)) { interface J : I { void __foo__(); } static if (functionLinkage!(J.__foo__) == "D") enum interfaceKind = InterfaceKind.native; else static if (functionLinkage!(J.__foo__) == "Windows") enum interfaceKind = InterfaceKind.windows; else static if (functionLinkage!(J.__foo__) == "C++") enum interfaceKind = InterfaceKind.cpp; else static assert(false, "Unknown interface kind."); } int main(string[] argv) { static assert(interfaceKind!NativeInterface == InterfaceKind.native); static assert(interfaceKind!COMInterface == InterfaceKind.windows); static assert(interfaceKind!CPPInterface == InterfaceKind.cpp); return 0; }
Aug 28 2015
parent Jacob Carlborg <doob me.com> writes:
On 2015-08-28 22:40, rumbu wrote:

 The linkage check it's good as long you don't have an abomination like
 this:

 extern(C++) interface CPPInterface
 {
      extern(D) void foo();
 }
Good point.
 Anyway, the problem is the availability of such function. If the
 interface doesn't contain any function, there is no way to detect the
 type, except for COM Interfaces which are clearly implementing IUnknown.

 But deriving a new interface and defining a sentinel function, it works:

 import std.stdio;
 import std.traits;
 import core.sys.windows.com;

 interface NativeInterface {}

 interface COMInterface : IUnknown {}

 extern(C++) interface CPPInterface {}

 enum InterfaceKind { native, windows, cpp }

 template interfaceKind(I) if (is(I == interface))
 {
      interface J : I { void __foo__(); }
      static if (functionLinkage!(J.__foo__) == "D")
          enum interfaceKind = InterfaceKind.native;
      else static if (functionLinkage!(J.__foo__) == "Windows")
          enum interfaceKind = InterfaceKind.windows;
      else static if (functionLinkage!(J.__foo__) == "C++")
          enum interfaceKind = InterfaceKind.cpp;
      else static assert(false, "Unknown interface kind.");
 }

 int main(string[] argv)
 {
     static assert(interfaceKind!NativeInterface == InterfaceKind.native);
     static assert(interfaceKind!COMInterface == InterfaceKind.windows);
     static assert(interfaceKind!CPPInterface == InterfaceKind.cpp);
     return 0;
 }
That looks like a pretty good idea, thanks. I'm wondering if it's worth implementing a trait for this in the compiler. -- /Jacob Carlborg
Aug 29 2015