Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 26, 2015 Class info on interfaces | ||||
---|---|---|---|---|
| ||||
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
|
August 26, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | 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.
|
August 26, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | 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 |
August 28, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | 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 |
August 28, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | 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. |
August 28, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | 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)
|
August 28, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | 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 |
August 28, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to rumbu | 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 |
August 28, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | 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; } |
August 29, 2015 Re: Class info on interfaces | ||||
---|---|---|---|---|
| ||||
Posted in reply to rumbu | 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 |
Copyright © 1999-2021 by the D Language Foundation