digitalmars.D.learn - Compile-type array of classes?
- Gordon (39/39) Feb 23 2014 Hello,
- anonymous (3/42) Feb 23 2014 import std.typetuple: TypeTuple;
- Gordon (63/69) Feb 23 2014 First, Thanks!
- Tobias Pankrath (8/78) Feb 23 2014 static methods are statically dispatched. Since they can called
- Steven Schveighoffer (14/31) Feb 23 2014 Note that Animal.name (Animal::name is C++, we use dots in D) does not
Hello, I'm sure this can be done, I'm just not sure what are the correct terms to search for... Given one interface, and multiple implementation classes, I want to create a list of the classes (in compile time). A contrived example: === interface Animal { static const string name() property; void make_noise(); } class Dog : Animal { static const string name() property { return "dog" ; } void make_noise() { writeln("Woof"); } } class Cat : Animal { static const string name() property { return "cat" ; } void make_noise() { writeln("Meow"); } } === What I want is: === static const xxxxx[] available_animals = [ dog, cat ]; === and then: === foreach (a; available_animals) { writeln("We have a ", a.name); } === Given that "name" is a static member function, it should be doable. But I'm not sure about the correct syntax of defining "available_animals". Any suggestions are welcomed, -gordon
Feb 23 2014
On Sunday, 23 February 2014 at 20:34:07 UTC, Gordon wrote:Hello, I'm sure this can be done, I'm just not sure what are the correct terms to search for... Given one interface, and multiple implementation classes, I want to create a list of the classes (in compile time). A contrived example: === interface Animal { static const string name() property; void make_noise(); } class Dog : Animal { static const string name() property { return "dog" ; } void make_noise() { writeln("Woof"); } } class Cat : Animal { static const string name() property { return "cat" ; } void make_noise() { writeln("Meow"); } } === What I want is: === static const xxxxx[] available_animals = [ dog, cat ]; === and then: === foreach (a; available_animals) { writeln("We have a ", a.name); } === Given that "name" is a static member function, it should be doable. But I'm not sure about the correct syntax of defining "available_animals". Any suggestions are welcomed, -gordonimport std.typetuple: TypeTuple; alias available_animals = TypeTuple!(Dog, Cat);
Feb 23 2014
On Sunday, 23 February 2014 at 20:52:58 UTC, anonymous wrote:On Sunday, 23 February 2014 at 20:34:07 UTC, Gordon wrote:First, Thanks! D is amazing :) Now, this lead me to a weird error. This is the complete (contrived) program: === import std.stdio, std.string, std.typetuple; interface Animal { static const string name() property; void make_noise(); } class Dog : Animal { static const string name() property { return "dog" ; } void make_noise() { writeln("woof"); } } class Cat : Animal { static const string name() property { return "cat" ; } void make_noise() { writeln("meow"); } } alias available_animals = TypeTuple!(Dog, Cat); void main() { string input_from_user = "dog"; Animal a; foreach (i; available_animals) { if (i.name == input_from_user) a = new i; } //// -- This doesn't compile --- //// writeln("The ", a.name, " makes: "); //// a.make_noise(); } === Running the program without the marked "writeln" works fine, as expected. Compiling with the marked writeln, produces an "underfined reference" error: ==== $ rdmd animals.d /tmp/.rdmd-34574/rdmd-animals.d-796CFD5A46BFE9DF13BF873F65EA 56C/objs/animals.o: In function `_Dmain': animals.d:(.text._Dmain+0xdf): undefined reference to `_D7animals6Animal4nameFNdZAya' collect2: error: ld returned 1 exit status --- errorlevel 1 ==== BTW - a work-around is simple, my question is about the theory behind this. I understand that "Animal::name" is undefined (since "Animal" is an interface). but if during runtime "a" has an actual type, why does the compiler looks for "Animal::name" instead of Dog::Name or Cat::Name (based on the type of "a") ? It is likely because of the "static", but if I remove the "static" than the 'foreach' loop won't compile, because "name" is not static. So this seems like some impossible situation...Given one interface, and multiple implementation classes, I want to create a list of the classes (in compile time).import std.typetuple: TypeTuple; alias available_animals = TypeTuple!(Dog, Cat);
Feb 23 2014
On Sunday, 23 February 2014 at 22:14:17 UTC, Gordon wrote:On Sunday, 23 February 2014 at 20:52:58 UTC, anonymous wrote:static methods are statically dispatched. Since they can called without an instance, they cannot be dispatched dynamically in general.On Sunday, 23 February 2014 at 20:34:07 UTC, Gordon wrote:First, Thanks! D is amazing :) Now, this lead me to a weird error. This is the complete (contrived) program: === import std.stdio, std.string, std.typetuple; interface Animal { static const string name() property; void make_noise(); } class Dog : Animal { static const string name() property { return "dog" ; } void make_noise() { writeln("woof"); } } class Cat : Animal { static const string name() property { return "cat" ; } void make_noise() { writeln("meow"); } } alias available_animals = TypeTuple!(Dog, Cat); void main() { string input_from_user = "dog"; Animal a; foreach (i; available_animals) { if (i.name == input_from_user) a = new i; } //// -- This doesn't compile --- //// writeln("The ", a.name, " makes: "); //// a.make_noise(); } === Running the program without the marked "writeln" works fine, as expected. Compiling with the marked writeln, produces an "underfined reference" error: ==== $ rdmd animals.d /tmp/.rdmd-34574/rdmd-animals.d-796CFD5A46BFE9DF13BF873F65EA 56C/objs/animals.o: In function `_Dmain': animals.d:(.text._Dmain+0xdf): undefined reference to `_D7animals6Animal4nameFNdZAya' collect2: error: ld returned 1 exit status --- errorlevel 1 ==== BTW - a work-around is simple, my question is about the theory behind this. I understand that "Animal::name" is undefined (since "Animal" is an interface). but if during runtime "a" has an actual type, why does the compiler looks for "Animal::name" instead of Dog::Name or Cat::Name (based on the type of "a") ?Given one interface, and multiple implementation classes, I want to create a list of the classes (in compile time).import std.typetuple: TypeTuple; alias available_animals = TypeTuple!(Dog, Cat);It is likely because of the "static", but if I remove the "static" than the 'foreach' loop won't compile, because "name" is not static.Correct.So this seems like some impossible situation...A non static method that forwards to the static one or comparison of the user input to the class names come to mind. Or use some instance of i to call (the non-static) method name.
Feb 23 2014
On Sun, 23 Feb 2014 17:14:16 -0500, Gordon <me home.com> wrote:Compiling with the marked writeln, produces an "underfined reference" error: ==== $ rdmd animals.d /tmp/.rdmd-34574/rdmd-animals.d-796CFD5A46BFE9DF13BF873F65EA 56C/objs/animals.o: In function `_Dmain': animals.d:(.text._Dmain+0xdf): undefined reference to `_D7animals6Animal4nameFNdZAya' collect2: error: ld returned 1 exit status --- errorlevel 1 ==== BTW - a work-around is simple, my question is about the theory behind this. I understand that "Animal::name" is undefined (since "Animal" is an interface).Note that Animal.name (Animal::name is C++, we use dots in D) does not define any requirements for derived mechanisms. And calling it on a base class or interface instance does not call the derived class' version. You should not make it static, it should be virtual. Otherwise, it will not be a virtual call. The reason you get the error is because it's trying to call Animal.name, and you haven't defined it.It is likely because of the "static", but if I remove the "static" than the 'foreach' loop won't compile, because "name" is not static.You don't need the whole static name business, D is better than that :) string input_from_user = "Dog"; // must be exact for this example, but you could use case insensitive compare if you wanted ... if(i.stringof == input_from_user) ... -Steve
Feb 23 2014