Interface "indexing"

2015-09-06 Thread Prudence via Digitalmars-d-learn

Suppose I have an interface

interface X(I)
{

}

Could it be possible for I to be an enum and then be able to 
"select" the specific interface at runtime based on the enum 
value?


I'm trying to avoid code like

switch (i)
{
   case I.myenumval1: return new X!myenumval1wrapper;
   ...
   case I.myenumvaln: return new X!myenumvalNwrapper;
}

Where myenumvalkwrapper are just types used for 
indexing/placeholders. X(I) is sort of like an enum of classes(or 
possibly objects)


enum X
{
   val1: class v1 { },
   val2: class v2 { },
   val3: class v3 { },
}

So if auto x = new X.val2() is the same as auto x = new v2(); And 
more importantly, auto x = new X!y(); where y is of type X(the 
enum part) and has value either val1, val2, val3.


(this example is obviously a little different, but if possible, 
would also solve my problem)


---

This helps with code bloat.

Suppose I have a series events and triggers. I could potentially 
code the specific events in an enum. And to fire the event, 
instead of a huge switch(or essentially the same), one can write 
one line of code or so and have D take care of matching up 
things. (essentially for some enum value I want a corresponding 
type to be associated with it)


I'm sure this would require some type of runtime reflection in 
the mapping or an automation of creating the switch code(duffs 
device?).


Any ideas?


Re: Interface "indexing"

2015-09-06 Thread Kagamin via Digitalmars-d-learn

On Sunday, 6 September 2015 at 17:32:11 UTC, Prudence wrote:
And to fire the event, instead of a huge switch(or essentially 
the same), one can write one line of code or so and have D take 
care of matching up things. (essentially for some enum value I 
want a corresponding type to be associated with it)


If you want it happen at runtime, how it can be not a switch?


Re: Interface "indexing"

2015-09-06 Thread Kagamin via Digitalmars-d-learn

Well, you can have an array of event factories:

IEvent function()[2] factories = [ factory1, factory2 ];

IEvent factory1() { return new Event1(); }
IEvent factory2() { return new Event2(); }

Then use enum for indexing:
IEvent e = factories[NumEvent1]();


Re: Interface "indexing"

2015-09-06 Thread Prudence via Digitalmars-d-learn

On Sunday, 6 September 2015 at 18:11:44 UTC, Kagamin wrote:

Well, you can have an array of event factories:

IEvent function()[2] factories = [ factory1, factory2 ];

IEvent factory1() { return new Event1(); }
IEvent factory2() { return new Event2(); }

Then use enum for indexing:
IEvent e = factories[NumEvent1]();


Yes, I suppose an array would work, but realize that since enum 
is a compile time construct, the dynamic array is not necessary. 
And since your factories are all the time and always will be(if 
you change anything you have to refactor a lot of stuff).


It seems all this stuff could be simplified a great deal. And no 
one said you wouldn't have a switch. I'm not talking about 
creating some tycheyon particles. I'm simply talking about some 
way to hide the details(which, could be done with a string mixin 
but at the cost of not being able to parse them and debug them 
well).





Re: Interface "indexing"

2015-09-06 Thread cym13 via Digitalmars-d-learn

On Sunday, 6 September 2015 at 18:16:02 UTC, Prudence wrote:

On Sunday, 6 September 2015 at 18:11:44 UTC, Kagamin wrote:

[...]


Yes, I suppose an array would work, but realize that since enum 
is a compile time construct, the dynamic array is not 
necessary. And since your factories are all the time and always 
will be(if you change anything you have to refactor a lot of 
stuff).


It seems all this stuff could be simplified a great deal. And 
no one said you wouldn't have a switch. I'm not talking about 
creating some tycheyon particles. I'm simply talking about some 
way to hide the details(which, could be done with a string 
mixin but at the cost of not being able to parse them and debug 
them well).


As you can do an enum with any type, why not an enum of factory?


Re: Interface "indexing"

2015-09-06 Thread anonymous via Digitalmars-d-learn
On Sunday 06 September 2015 19:32, Prudence wrote:

> Any ideas?

As far as I understand (which may not be very far), you'd like to avoid 
keeping a list of the types that's separate from the type declarations 
themselves.

Let's start with some code where the list is manually kept in sync with the 
types:


import std.stdio;
import std.typetuple;

interface I {void go();}

class A : I {void go() {writeln("'Allo 'Allo!");}}
class B : I {void go() {writeln("Bonjourno!");}}
class C : I {void go() {writeln("Cha cha ciao!");}}

alias Types = TypeTuple!(A, B, C); /* You'd like to avoid this, right? */

I create(uint index)
{
switch(index)
{
/* Note how the switch cases are generated with (static) foreach: */
foreach(i, T; Types)
case i: return new T;
default: throw new Exception("");
}
}

void main()
{
auto a = create(0);
a.go(); /* 'Allo 'Allo! */

auto b = create(1);
b.go(); /* Bonjourno! */

auto c = create(2);
c.go(); /* Cha cha ciao! */

auto d = create(3); /* throws exception */
}


To avoid having to touch two places when you add a class, you can use a 
somewhat obscure feature of D, the NewAnonClassExpression:


alias Types = TypeTuple!(
typeof(new class () I {void go() {writeln("'Allo 'Allo!");}}),
typeof(new class () I {void go() {writeln("Bonjourno!");}}),
typeof(new class () I {void go() {writeln("Cha cha ciao!");}}),
);


The syntax is described here: http://dlang.org/class.html#anonymous

Another alternative is to generate `Types` by getting all members of the 
module and filtering out everything that doesn't implement I:


class A : I {void go() {writeln("'Allo 'Allo!");}}
class B : I {void go() {writeln("Bonjourno!");}}
class C : I {void go() {writeln("Cha cha ciao!");}}

template IfImplementsI(string thing_s)
{
alias thing = TypeTuple!(__traits(getMember, module_, thing_s));
static if (is(thing[0] : I) && !is(thing[0] == I))
alias IfImplementsI = thing;
else alias IfImplementsI = TypeTuple!();
}

alias module_ = TypeTuple!(__traits(parent, {}));
alias Types = staticMap!(IfImplementsI, __traits(allMembers, module_));


That can probably be done more elegantly.

I'm sure one could also generate an enum with nice names along with that, so 
that it's not `create(0)` but `create(MyEnum.A)`.