www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Compile-type array of classes?

reply "Gordon" <me home.com> writes:
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
parent reply "anonymous" <anonymous example.com> writes:
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);
Feb 23 2014
parent reply "Gordon" <me home.com> writes:
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-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...
Feb 23 2014
next sibling parent "Tobias Pankrath" <tobias pankrath.net> writes:
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-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") ?
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.
Feb 23 2014
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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