www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Reflection: Get all inherited classes of a base class

reply "nrgyzer" <nrgyzer unknownMailAddress.com> writes:
Hi everyone,

is it possible to get a list of all inherited classes from a base 
class like this:

class A {
    ...
}
class B : A {
    ...
}
class C : A {
    ...
}
class D : B {
    ...
}

auto myClasses = __traits(allInheritedClasses, A); // I'm looking 
for something like this.
assert(myClasses, [B.classinfo, C.classinfo, D.classinfo]);

All I found wasn't exactly what I need, hence I hope there is any 
chance to do something like that or is there currently no chance?

Thanks for any advice!
Dec 22 2012
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Saturday, 22 December 2012 at 22:14:28 UTC, nrgyzer wrote:
 is it possible to get a list of all inherited classes from a 
 base class like this:
Yes, though it isn't compile time - gotta be runtime. ClassInfo[] getChildClasses(ClassInfo c) { ClassInfo[] info; // MoudleInfo is a magical thing in object.d, // implicitly imported, that can loop over all // modules in the program: user and library foreach(mod; ModuleInfo) { // the localClasses member gives back // ClassInfo things that we can compare foreach(cla; mod.localClasses) { // note: we could also check this // recursively and check // cla.interfaces as well as base if(cla.base is c) info ~= cla; } } return info; } So this should be enough for your example assert, but remember you can't do things like templates on this, since it is all runtime.
Dec 22 2012
parent reply "nrgyzer" <nrgyzer unknownMailAddress.com> writes:
On Saturday, 22 December 2012 at 22:28:57 UTC, Adam D. Ruppe 
wrote:
 On Saturday, 22 December 2012 at 22:14:28 UTC, nrgyzer wrote:
 is it possible to get a list of all inherited classes from a 
 base class like this:
Yes, though it isn't compile time - gotta be runtime. ClassInfo[] getChildClasses(ClassInfo c) { ClassInfo[] info; // MoudleInfo is a magical thing in object.d, // implicitly imported, that can loop over all // modules in the program: user and library foreach(mod; ModuleInfo) { // the localClasses member gives back // ClassInfo things that we can compare foreach(cla; mod.localClasses) { // note: we could also check this // recursively and check // cla.interfaces as well as base if(cla.base is c) info ~= cla; } } return info; } So this should be enough for your example assert, but remember you can't do things like templates on this, since it is all runtime.
Thanks Adam, that's exactly what I need... is it possible to call a static method only using TypeInfo_Class or do I need to call the constructor using create-method? I think using annotation would be very helpful for my idea: abstract class A { static abstract string myName(); // this surely doesn't work string[] getChildClassNames() { string[] retArray; foreach(mod; ModuleInfo) { foreach(cla; mod.localClasses) { if (cla is this.classinfo) retArray ~= cla.myName; // adds "Class B" and "Class C" } return retArray; } } class B : A { override static string myName() { return "Class B"; } } class C : A { override static string myName() { return "Class C"; } } But as in the most other languages it's impossible to declare abstract static methods and I also have no direct access from TypeInfo_Class to my static attributes and/or methods (or is there any chance without creating an instance of the class?). Hence, annotations would be very useful at this point, but is there any other possibility to do something like shown above...?
Dec 25 2012
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-12-25 19:26, nrgyzer wrote:

 Thanks Adam, that's exactly what I need... is it possible to call a
 static method only using TypeInfo_Class or do I need to call the
 constructor using create-method? I think using annotation would be very
 helpful for my idea:
As far as I know you cannot call any method using TypeInfo_Class.
 abstract class A {
 static abstract string myName(); // this surely doesn't work
 string[] getChildClassNames() {
 string[] retArray;
 foreach(mod; ModuleInfo) {
 foreach(cla; mod.localClasses) {
 if (cla is this.classinfo)
 retArray ~= cla.myName; // adds "Class B" and "Class C"
 }
 return retArray;
 }
 }

 class B : A {
 override static string myName() { return "Class B"; }
 }

 class C : A {
 override static string myName() { return "Class C"; }
 }

 But as in the most other languages it's impossible to declare abstract
 static methods and I also have no direct access from TypeInfo_Class to
 my static attributes and/or methods (or is there any chance without
 creating an instance of the class?).

 Hence, annotations would be very useful at this point, but is there any
 other possibility to do something like shown above...?
You can get the name of a class using "this.classinfo.name" or from any other TypeInfo_Class. -- /Jacob Carlborg
Dec 26 2012
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 25 December 2012 at 18:26:29 UTC, nrgyzer wrote:
 Thanks Adam, that's exactly what I need... is it possible to 
 call a static method only using TypeInfo_Class or do I need to 
 call the constructor using create-method?
No, to call a static method you'd have to get to the compile time class; you'd have to actually do A.myName or cast(A) on a created object. Like Jacob said though, the name is available as classinfo.name. Anything else would best be done with an interface you can cast to and call some abstract methods. BTW, it is potentially possible to do something with the magic RTInfo but I don't think that's available outside the druntime, so while we could potentially do more in theory, in practice probably not right now. We'd have to work something out between druntime and user extensibility.
Dec 26 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, December 22, 2012 23:14:28 nrgyzer wrote:
 Hi everyone,
 
 is it possible to get a list of all inherited classes from a base
 class like this:
 
 class A {
     ...
 }
 class B : A {
     ...
 }
 class C : A {
     ...
 }
 class D : B {
     ...
 }
 
 auto myClasses = __traits(allInheritedClasses, A); // I'm looking
 for something like this.
 assert(myClasses, [B.classinfo, C.classinfo, D.classinfo]);
 
 All I found wasn't exactly what I need, hence I hope there is any
 chance to do something like that or is there currently no chance?
No, it's not possible. Derived classes don't have to be compiled at the same time as the base class. For instance, the base class could be in a library, and the derived class could be in a program which is linked against that library years after the library was compiled. And if you have shared libraries, then more classes could be added to the program months or years after the program started if they're loaded while the program is running. Granted, you probably won't be running a program for years, but given how D's compilation model works, it's something that you can do if your program runs long enough, and loading shared libraries after the program has been running for a while isn't all that uncommon, even if it's only minutes later rather than years (plugins are a good example of that sort of thing). So, given D's compilation model, it's not even theoretically possible to get a list like that, let alone actually possible. Best case, if each class registered its existance when it was loaded into the environment (e.g with a static constructor), then you could get a list of the classes which are currently loaded, but that's not at all what you're asking for here, and you'd have to create such a registration mechanism yourself, because no such thing is provided by the runtime. - Jonathan M Davis
Dec 22 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, December 22, 2012 14:26:23 Jonathan M Davis wrote:
 Best case, if each class
 registered its existance when it was loaded into the environment (e.g with
 a static constructor), then you could get a list of the classes which are
 currently loaded, but that's not at all what you're asking for here, and
 you'd have to create such a registration mechanism yourself, because no
 such thing is provided by the runtime.
It looks like the runtime _does_ give you this capability (as Adam explains in his reponse), so I stand corrected on that point. But a compile time solution is still impossible due to D's compilation model. - Jonathan M Davis
Dec 22 2012
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
 It looks like the runtime _does_ give you this capability (as Adam
 explains in
 his reponse), so I stand corrected on that point. But a compile time
 solution
 is still impossible due to D's compilation model.
A possible, partial solution is to get a module members at compile-time and iterate on them to see if they are subclasses of A. That's partial for the reasons you cited, but that might be enough for the OP. I don't remember: is there a way to get all visible symbols in the current scope?
Dec 23 2012