Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
February 23, 2014 Compile-type array of classes? | ||||
---|---|---|---|---|
| ||||
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 |
February 23, 2014 Re: Compile-type array of classes? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gordon | 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,
> -gordon
import std.typetuple: TypeTuple;
alias available_animals = TypeTuple!(Dog, Cat);
|
February 23, 2014 Re: Compile-type array of classes? | ||||
---|---|---|---|---|
| ||||
Posted in reply to anonymous | On Sunday, 23 February 2014 at 20:52:58 UTC, anonymous wrote: > On Sunday, 23 February 2014 at 20:34:07 UTC, Gordon wrote: >> >> 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); 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-796CFD5A46BFE9DF13BF873F65EA656C/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... |
February 23, 2014 Re: Compile-type array of classes? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gordon | On Sunday, 23 February 2014 at 22:14:17 UTC, Gordon wrote: > On Sunday, 23 February 2014 at 20:52:58 UTC, anonymous wrote: >> On Sunday, 23 February 2014 at 20:34:07 UTC, Gordon wrote: >>> >>> 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); > > 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-796CFD5A46BFE9DF13BF873F65EA656C/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") ? static methods are statically dispatched. Since they can called without an instance, they cannot be dispatched dynamically in general. > 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. |
February 24, 2014 Re: Compile-type array of classes? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gordon | 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-796CFD5A46BFE9DF13BF873F65EA656C/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 |
Copyright © 1999-2021 by the D Language Foundation