www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - getting all children classes in program

reply "Ondra" <pokorny.ondrej gmail.com> writes:
Hi,

how can I get list of all children classes of class in program? I 
was trying to use ModuleInfo from D Coockbook but this does not 
work for template classes?

ex.:
class A{}
class B:A{} // ok in ModuleInfo
class C(T): B {} // missing in ModuleInfo

I am trying to assign every class its unique ID that is same for 
all instances.

Code:
int result[string];

	int counter = 0;
	foreach(mod; ModuleInfo)
	{
		foreach(cla; mod.localClasses)
		{
		  	auto base = cla.base;
		  	while (base)
		  	{
		  		if (base is T.classinfo)
			  	{
			  		result[cla.name] = counter;
			  		
			  		counter++;
			  	}

			  	base = base.base;
		  	}
		}
	}
Jan 03 2015
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Saturday, 3 January 2015 at 14:28:07 UTC, Ondra wrote:
 class C(T): B {} // missing in ModuleInfo
The reason is that's technically not a class and doesn't exist at runtime, it is just a template for one (you can't new that, you'd have to new C!some_actual_type). If you were to add a class D : C!int {} then you'd see class D shows up and has a parent of C!int... however, you're right, C!int doesn't want to show up at all, even if I instantiate it. I'm not sure if there's a way around that other than to add some code in the class to register itself. You could use a static constructor that adds itself to a list. Or, to give each class a shared ID, you could add a static member which returns some variation of its typeinfo. In fact, typeid(any_class) returns a unique identifier for each class (an instance of TypeInfo), maybe you can use it directly.
Jan 03 2015
parent reply "Ondra" <pokorny.ondrej gmail.com> writes:
 I'm not sure if there's a way around that other than to add 
 some code in the class to register itself. You could use a 
 static constructor that adds itself to a list.

 Or, to give each class a shared ID, you could add a static 
 member which returns some variation of its typeinfo. In fact, 
 typeid(any_class) returns a unique identifier for each class 
 (an instance of TypeInfo), maybe you can use it directly.
Hi Adam, static this is probably way to go, I wanted to avoid this solution because if it leads to copy-pasting code to every child. I need to have IDs small like 8bits, co I probably can't use typeid... Thank you for answer. Knowing that someting cannot be done is better than spend on this another few hour. Great book btw. Ondra
Jan 03 2015
parent reply "Baz" <bb.temp gmx.com> writes:
On Saturday, 3 January 2015 at 15:00:53 UTC, Ondra wrote:
 I'm not sure if there's a way around that other than to add 
 some code in the class to register itself. You could use a 
 static constructor that adds itself to a list.

 Or, to give each class a shared ID, you could add a static 
 member which returns some variation of its typeinfo. In fact, 
 typeid(any_class) returns a unique identifier for each class 
 (an instance of TypeInfo), maybe you can use it directly.
Hi Adam, static this is probably way to go, I wanted to avoid this solution because if it leads to copy-pasting code to every child. I need to have IDs small like 8bits, co I probably can't use typeid... Thank you for answer. Knowing that someting cannot be done is better than spend on this another few hour. Great book btw. Ondra
Hello, here is another solution: a class ID is generated lazily, when queried It does not recquire a static constructor. ---- module runnable; static string[] IDs; ptrdiff_t getClassID(ClassType)() if (is(ClassType == class)) { import std.algorithm; auto classTypeString = ClassType.stringof; ptrdiff_t result = countUntil(IDs, classTypeString); if (result == -1) { IDs ~= classTypeString; result = IDs.length -1; } return result; } void main(string[] args) { class A{} class B{} class C{} class D{} assert(getClassID!A == 0); assert(getClassID!B == 1); assert(getClassID!C == 2); assert(getClassID!D == 3); assert(getClassID!C == 2); assert(getClassID!B == 1); assert(getClassID!A == 0); } ---- Hoping it matches to your needs.
Jan 03 2015
parent reply "jklp" <jklp nowhere.fr> writes:
Off Topic ! But in the same way:

-------
static string[] IDs;

ptrdiff_t getClassID(ClassType, ClassBase)()
if ((is(ClassType == class)) && (is(ClassBase == class)))
{
     import std.algorithm;
     if (!is(ClassType : ClassBase))
         return -1;
     else {
         auto classTypeString = ClassType.stringof;
         ptrdiff_t result = countUntil(IDs, classTypeString);
         if (result == -1) {
             IDs ~= classTypeString;
             result = IDs.length -1;
         }
         return result;
     }
}

void main(string[] args)
{
     class Oops {}
     class A : Oops{}
     class B : Oops{}
     class C : Oops{}
     class D : Oops{}
     class E {}

     assert(getClassID!(A,Oops) == 0);
     assert(getClassID!(B,Oops) == 1);
     assert(getClassID!(C,Oops) == 2);
     assert(getClassID!(D,Oops) == 3);
     assert(getClassID!(C,Oops) == 2);
     assert(getClassID!(B,Oops) == 1);
     assert(getClassID!(A,Oops) == 0);
     assert(getClassID!(E,Oops) == -1);
}
-------
Jan 03 2015
parent "Ondra" <pokorny.ondrej gmail.com> writes:
Hi Baz & jklp,

thank you for ideas I will use your approach for this problem.
Jan 03 2015