www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Getting derived classes

reply dsimcha <dsimcha yahoo.com> writes:
I know that, in std.traits, there's a template that spits out all base classes
for a given class.  Based on reading the source, it seems to work based on a
rather interesting use case for is expressions.  Is there any equivalent way
to do the opposite:  For any given position in a class hierarchy, to get a
tuple of all possible descendants?
Oct 16 2008
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base classes
 for a given class.  Based on reading the source, it seems to work based on a
 rather interesting use case for is expressions.  Is there any equivalent way
 to do the opposite:  For any given position in a class hierarchy, to get a
 tuple of all possible descendants?

That's not possible in general because in D the derived classes form an open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time. Andrei
Oct 16 2008
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base classes
 for a given class.  Based on reading the source, it seems to work based on a
 rather interesting use case for is expressions.  Is there any equivalent way
 to do the opposite:  For any given position in a class hierarchy, to get a
 tuple of all possible descendants?

open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time. Andrei

Not quite sure I understand why this has to be the case. Somewhere in the docs, Walter explicitly says that, since D knows about the whole class tree, the compiler can figure out which functions in a hierarchy can be made non-virtual. If this is the case, why is the compiler not able to know about the whole class tree for purposes of creating lists of derived classes?
Oct 16 2008
next sibling parent Jason House <jason.james.house gmail.com> writes:
dsimcha wrote:

 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 article
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base
 classes
 for a given class.  Based on reading the source, it seems to work based
 on a
 rather interesting use case for is expressions.  Is there any
 equivalent way
 to do the opposite:  For any given position in a class hierarchy, to
 get a tuple of all possible descendants?

open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time. Andrei

Not quite sure I understand why this has to be the case. Somewhere in the docs, Walter explicitly says that, since D knows about the whole class tree, the compiler can figure out which functions in a hierarchy can be made non-virtual. If this is the case, why is the compiler not able to know about the whole class tree for purposes of creating lists of derived classes?

There are many things hiding somewhere in the docs are many things that are not implemented :)
Oct 16 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
dsimcha wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base classes
 for a given class.  Based on reading the source, it seems to work based on a
 rather interesting use case for is expressions.  Is there any equivalent way
 to do the opposite:  For any given position in a class hierarchy, to get a
 tuple of all possible descendants?

open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time. Andrei

Not quite sure I understand why this has to be the case. Somewhere in the docs, Walter explicitly says that, since D knows about the whole class tree, the compiler can figure out which functions in a hierarchy can be made non-virtual. If this is the case, why is the compiler not able to know about the whole class tree for purposes of creating lists of derived classes?

I think the actual implementation of this is somewhat different. Rather than relying on knowledge of the entire class tree, the compiler simply has to know what type a particular function is being called on. For example: class C { void fn() {} } void main() { auto c = new C; c.fn(); } Here, the compiler knows that it's dealing with an instance of C rather than a possibly unknown derived class so it can call fn() directly rather than going through the vtbl. However: void callFn( C c ) { c.fn(); } Here, the compiler doesn't know what the underlying type is so it must go through the vtbl. Sean
Oct 16 2008
parent Jason House <jason.james.house gmail.com> writes:
Sean Kelly Wrote:

 dsimcha wrote:
 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s article
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base classes
 for a given class.  Based on reading the source, it seems to work based on a
 rather interesting use case for is expressions.  Is there any equivalent way
 to do the opposite:  For any given position in a class hierarchy, to get a
 tuple of all possible descendants?

open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time. Andrei

Not quite sure I understand why this has to be the case. Somewhere in the docs, Walter explicitly says that, since D knows about the whole class tree, the compiler can figure out which functions in a hierarchy can be made non-virtual. If this is the case, why is the compiler not able to know about the whole class tree for purposes of creating lists of derived classes?

I think the actual implementation of this is somewhat different. Rather than relying on knowledge of the entire class tree, the compiler simply has to know what type a particular function is being called on. For example: class C { void fn() {} } void main() { auto c = new C; c.fn(); } Here, the compiler knows that it's dealing with an instance of C rather than a possibly unknown derived class so it can call fn() directly rather than going through the vtbl. However: void callFn( C c ) { c.fn(); } Here, the compiler doesn't know what the underlying type is so it must go through the vtbl. Sean

The compiler could be smarter than that, but isn't. I too was tricked by the same bit of D documentation. Avoiding virtual calls can be a significant speed gain. I have final functions throughout my code because gdc was too stupid to recognize they could be.
Oct 17 2008
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
dsimcha <dsimcha yahoo.com> писал(а) в своём письме Fri, 17
Oct 2008  
06:18:34 +0400:

 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s  
 article
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all  

 for a given class.  Based on reading the source, it seems to work  

 rather interesting use case for is expressions.  Is there any  

 to do the opposite:  For any given position in a class hierarchy, to  

 tuple of all possible descendants?

open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time. Andrei

Not quite sure I understand why this has to be the case. Somewhere in the docs, Walter explicitly says that, since D knows about the whole class tree, the compiler can figure out which functions in a hierarchy can be made non-virtual. If this is the case, why is the compiler not able to know about the whole class tree for purposes of creating lists of derived classes?

How do you get a list of all classes that derive from Object? I might write one, too! Imagine we compile the source separately and then link obj files together.
Oct 16 2008
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Andrei Alexandrescu escribió:
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base 
 classes
 for a given class.  Based on reading the source, it seems to work 
 based on a
 rather interesting use case for is expressions.  Is there any 
 equivalent way
 to do the opposite:  For any given position in a class hierarchy, to 
 get a
 tuple of all possible descendants?

That's not possible in general because in D the derived classes form an open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time.

But for a given set of modules, the hierarchy is finite and known.
 
 Andrei

Oct 17 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Ary Borenszweig" wrote
 Andrei Alexandrescu escribi:
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base 
 classes
 for a given class.  Based on reading the source, it seems to work based 
 on a
 rather interesting use case for is expressions.  Is there any equivalent 
 way
 to do the opposite:  For any given position in a class hierarchy, to get 
 a
 tuple of all possible descendants?

That's not possible in general because in D the derived classes form an open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time.

But for a given set of modules, the hierarchy is finite and known.

Not at compile time, only at link time. You can't compile code at link time. -Steve
Oct 17 2008
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Steven Schveighoffer wrote:
 "Ary Borenszweig" wrote
 Andrei Alexandrescu escribi:
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base 
 classes
 for a given class.  Based on reading the source, it seems to work based 
 on a
 rather interesting use case for is expressions.  Is there any equivalent 
 way
 to do the opposite:  For any given position in a class hierarchy, to get 
 a
 tuple of all possible descendants?

open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time.


Not at compile time, only at link time. You can't compile code at link time.

I still don't understand why you can't do this at compile time, assuming you have the source code for everything that you'll link into your executable. How is a class hierarchy different in D than in Java? Eclipse JDT's has a type hierarchy feature, and Bruno was going to implement it in Mrnmhrm, all based on what's defined in the modules (you can say, compilte-time). What's the problem?
 
 -Steve 
 
 

Oct 17 2008
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Ary Borenszweig" wrote
 Steven Schveighoffer wrote:
 "Ary Borenszweig" wrote
 Andrei Alexandrescu escribi:
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base 
 classes
 for a given class.  Based on reading the source, it seems to work 
 based on a
 rather interesting use case for is expressions.  Is there any 
 equivalent way
 to do the opposite:  For any given position in a class hierarchy, to 
 get a
 tuple of all possible descendants?

open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time.


Not at compile time, only at link time. You can't compile code at link time.

I still don't understand why you can't do this at compile time, assuming you have the source code for everything that you'll link into your executable.

Let's say this feature theoretically existed. Here's an example usage: class X { Tuple!(???) getAllDerivedTypes() { return std.getAllDerivedTypes!(X)();} } If you compile this module like: dmd -c X.d; At this point, how does the compiler know all the modules that will derive from X? D's compile-time reflection is generally limited to what is at or below a certain point in the hierarchy, not what has derived from it. If you wanted to do something at runtime, that is possible, you might even be able to do this today by looking at the global TypeInfo array. But you certainly cannot get a tuple of the derived classes at compile-time.
 How is a class hierarchy different in D than in Java? Eclipse JDT's has a 
 type hierarchy feature, and Bruno was going to implement it in Mrnmhrm, 
 all based on what's defined in the modules (you can say, compilte-time). 
 What's the problem?

Java has runtime reflection. D does not. You have to implement runtime reflection on top of compile time reflection (or so says Walter). There should be no problem if you want the information at runtime. But a Tuple is a compile-time entity. You can probably get the TypeInfos of the classes, but not really be able to do much, since D's runtime reflection capabilities are limited. -Steve
Oct 17 2008
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Steven Schveighoffer wrote:
 "Ary Borenszweig" wrote
 Steven Schveighoffer wrote:
 "Ary Borenszweig" wrote
 Andrei Alexandrescu escribi:
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base 
 classes
 for a given class.  Based on reading the source, it seems to work 
 based on a
 rather interesting use case for is expressions.  Is there any 
 equivalent way
 to do the opposite:  For any given position in a class hierarchy, to 
 get a
 tuple of all possible descendants?

open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time.


time.

you have the source code for everything that you'll link into your executable.

Let's say this feature theoretically existed. Here's an example usage: class X { Tuple!(???) getAllDerivedTypes() { return std.getAllDerivedTypes!(X)();} } If you compile this module like: dmd -c X.d; At this point, how does the compiler know all the modules that will derive from X?

Well explained.
 D's compile-time reflection is generally limited to what is at or below a 
 certain point in the hierarchy, not what has derived from it.

s/below/above/
 If you wanted to do something at runtime, that is possible, you might even 
 be able to do this today by looking at the global TypeInfo array.
 
 But you certainly cannot get a tuple of the derived classes at compile-time.
 
 How is a class hierarchy different in D than in Java? Eclipse JDT's has a 
 type hierarchy feature, and Bruno was going to implement it in Mrnmhrm, 
 all based on what's defined in the modules (you can say, compilte-time). 
 What's the problem?

Java has runtime reflection. D does not. You have to implement runtime reflection on top of compile time reflection (or so says Walter).

I said so. All derived classes is, however, a case of runtime-available information that's not there during compilation. Anyhow, there's a start with the function static Object.factory(string). You give it a string, it gives you a newly-instanced object. So the information is there, it just needs exposing. Andrei
Oct 17 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
Andrei Alexandrescu wrote:
 
 Anyhow, there's a start with the function static Object.factory(string).
 You give it a string, it gives you a newly-instanced object. So the
 information is there, it just needs exposing.

Much of it is even exposed, just not in a convenient manner. A list of classes is available via ModuleInfo, and ClassInfo provides a means of finding the ClassInfo instance of a class by name. From there it should be possible to obtain a list of parent classes, and so one could build a hierarchy graph with some work. Sean
Oct 17 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Sean Kelly" wrote
 Andrei Alexandrescu wrote:
 Anyhow, there's a start with the function static Object.factory(string).
 You give it a string, it gives you a newly-instanced object. So the
 information is there, it just needs exposing.

Much of it is even exposed, just not in a convenient manner. A list of classes is available via ModuleInfo, and ClassInfo provides a means of finding the ClassInfo instance of a class by name. From there it should be possible to obtain a list of parent classes, and so one could build a hierarchy graph with some work.

Sure, but what do you do with that graph ;) Calling methods/ctors is not exactly easy with D currently. -Steve
Oct 17 2008
parent Christopher Wright <dhasenan gmail.com> writes:
Steven Schveighoffer wrote:
 "Sean Kelly" wrote
 Andrei Alexandrescu wrote:
 Anyhow, there's a start with the function static Object.factory(string).
 You give it a string, it gives you a newly-instanced object. So the
 information is there, it just needs exposing.

classes is available via ModuleInfo, and ClassInfo provides a means of finding the ClassInfo instance of a class by name. From there it should be possible to obtain a list of parent classes, and so one could build a hierarchy graph with some work.

Sure, but what do you do with that graph ;) Calling methods/ctors is not exactly easy with D currently. -Steve

Parameterless constructors are easy. Other than that, you can't be certain what expectations the constructor has, so it's a bit dangerous, but you can of course get around that with documentation and try/catch. Calling methods isn't so difficult, either, since most of the stuff you'll be able to do involves virtual methods from some known base class. Dunit uses runtime reflection to get all test fixtures and run them. It uses something like: ClassInfo[] derived(ClassInfo info) { ClassInfo[] derivedClasses; foreach (module; ModuleInfo) foreach (clazz; module.localClasses) { if (isDerived(clazz; info)) derivedClasses ~= clazz; } return derivedClasses; } // Only works for interfaces. bool isDerived(ClassInfo derived, ClassInfo base) { while (derived) { if (base is derived) return true; derived = derived.base; } } I did this because I was tired of the static ctor mixin / static singleton registration pattern. I used to have to do: class FooTests : TestFixture { // I already told you it's a test fixture! // You mean I have to tell you twice?! mixin (DunitTest); } Now I can skip the mixin.
Nov 01 2008
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Ary Borenszweig wrote:
 Steven Schveighoffer wrote:
 "Ary Borenszweig" wrote
 Andrei Alexandrescu escribi:
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all 
 base classes
 for a given class.  Based on reading the source, it seems to work 
 based on a
 rather interesting use case for is expressions.  Is there any 
 equivalent way
 to do the opposite:  For any given position in a class hierarchy, 
 to get a
 tuple of all possible descendants?

an open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time.


Not at compile time, only at link time. You can't compile code at link time.

I still don't understand why you can't do this at compile time, assuming you have the source code for everything that you'll link into your executable. How is a class hierarchy different in D than in Java? Eclipse JDT's has a type hierarchy feature, and Bruno was going to implement it in Mrnmhrm, all based on what's defined in the modules (you can say, compilte-time). What's the problem?

It would be possible for the compiler to determine subtypes, if, just like an IDE or build tool, the compiler had a well structured concept of a project (ie, a set of source folders, libraries, included modules, etc.). But just because it is possible, doesn't mean it's desirable, and in fact, it isn't. It's senseless: Such code (ie, getting all derived types) would introduce an open-ended compile-time coupling, as a module using that functionality would depended on *every* other module of the project. And that makes such functionality compilable only in projects that compile into an executable (which is when the set of dependencies is finite). That is, you couldn't use that functionality in a library, which shows much of an inane idea it is. It's breaking an abstraction barrier. Getting that information at *runtime* might be sensible, but I'm not seeing much usefulness in that. -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Oct 21 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
Bruno Medeiros wrote:
 Getting that information at *runtime* might be sensible, but I'm not 
 seeing much usefulness in that.

The main use case I can see is a plugin solution. For example, automatically instantiate all classes that extend IPlugin or something. However, requiring a config file that includes the class name and maybe some metadata isn't too hard to do and is potentially more efficient.
Oct 21 2008
prev sibling parent BLS <nanali nospam-wanadoo.fr> writes:
Andrei Alexandrescu schrieb:
 dsimcha wrote:
 I know that, in std.traits, there's a template that spits out all base 
 classes
 for a given class.  Based on reading the source, it seems to work 
 based on a
 rather interesting use case for is expressions.  Is there any 
 equivalent way
 to do the opposite:  For any given position in a class hierarchy, to 
 get a
 tuple of all possible descendants?

That's not possible in general because in D the derived classes form an open set. I guess it could be done at runtime via reflection (not implemented afaik), but not at compile time. Andrei

-> Jacha Wetzel Here is a simple way of adding __traits based runtime reflection to D classes: http://mainia.de/classinfoex.d (requires DMD 2.004)
Nov 01 2008
prev sibling next sibling parent reply BCS <ao pathlink.com> writes:
Reply to dsimcha,

 I know that, in std.traits, there's a template that spits out all base
 classes for a given class.  Based on reading the source, it seems to
 work based on a rather interesting use case for is expressions.  Is
 there any equivalent way to do the opposite:  For any given position
 in a class hierarchy, to get a tuple of all possible descendants?
 

Via DLL/SO's, a derived class can be /written/ after the program that it will be used in is /compiled/. Because of that (and other less restrictive forms of that issue) The most general answer is; can't be done.
Oct 17 2008
parent Don <nospam nospam.com.au> writes:
Jarrett Billingsley wrote:
 On Fri, Oct 17, 2008 at 5:34 PM, Bill Baxter <wbaxter gmail.com> wrote:
 
 I wonder what Object.Factory does when you try to make a class from a
 DLL like that.

 I'm guessing it doesn't work.

I think you've guessed correctly. DLLs, in general, are next to useless with D.

Rather: A D app and a D DLL can only communicate via extern(C) interfaces. Or via COM. It's not great, but it isn't any worse than DLLs in C++.
Oct 20 2008
prev sibling next sibling parent reply "Bill Baxter" <wbaxter gmail.com> writes:
On Sat, Oct 18, 2008 at 6:20 AM, BCS <ao pathlink.com> wrote:
 Reply to dsimcha,

 I know that, in std.traits, there's a template that spits out all base
 classes for a given class.  Based on reading the source, it seems to
 work based on a rather interesting use case for is expressions.  Is
 there any equivalent way to do the opposite:  For any given position
 in a class hierarchy, to get a tuple of all possible descendants?

Via DLL/SO's, a derived class can be /written/ after the program that it will be used in is /compiled/. Because of that (and other less restrictive forms of that issue) The most general answer is; can't be done.

I wonder what Object.Factory does when you try to make a class from a DLL like that. I'm guessing it doesn't work. --bb
Oct 17 2008
parent BCS <ao pathlink.com> writes:
Reply to Bill,

 On Sat, Oct 18, 2008 at 6:20 AM, BCS <ao pathlink.com> wrote:
 
 Reply to dsimcha,
 
 I know that, in std.traits, there's a template that spits out all
 base classes for a given class.  Based on reading the source, it
 seems to work based on a rather interesting use case for is
 expressions.  Is there any equivalent way to do the opposite:  For
 any given position in a class hierarchy, to get a tuple of all
 possible descendants?
 

it will be used in is /compiled/. Because of that (and other less restrictive forms of that issue) The most general answer is; can't be done.

DLL like that. I'm guessing it doesn't work. --bb

it might work by hiding a static this function that registries the class, from that, when the dll lodes the class is registered.
Oct 17 2008
prev sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Fri, Oct 17, 2008 at 5:34 PM, Bill Baxter <wbaxter gmail.com> wrote:

 I wonder what Object.Factory does when you try to make a class from a
 DLL like that.

 I'm guessing it doesn't work.

I think you've guessed correctly. DLLs, in general, are next to useless with D.
Oct 17 2008