creating a variadic interface

2013-07-08 Thread JS


this may seem a bit nonsensical but it is just an example:

interface A(T, S...)
{
   ... Generate a getter for each type in S...
   // e.g., @property S[0] property1();
   //   @property S[1] property2();
   // 
}

I imagine I have to use a mixin template but I'm unsure how to 
create a static loop that can be used properly.


I think maybe using mixin's of mixin's is possible but I can't 
think of any simple way. Any ideas?


Re: creating a variadic interface

2013-07-08 Thread John Colvin

On Monday, 8 July 2013 at 09:34:46 UTC, JS wrote:


this may seem a bit nonsensical but it is just an example:

interface A(T, S...)
{
   ... Generate a getter for each type in S...
   // e.g., @property S[0] property1();
   //   @property S[1] property2();
   // 
}

I imagine I have to use a mixin template but I'm unsure how to 
create a static loop that can be used properly.


I think maybe using mixin's of mixin's is possible but I can't 
think of any simple way. Any ideas?


Here you go :)

//just to hide the string mixin.
mixin template Getters(S ...)
{
mixin(GettersImpl!S);
}

import std.conv : to;
template GettersImpl(S ...)
{
static if(S.length == 0)
{
enum GettersImpl = "";
}
else static if(S.length == 1)
{
		enum GettersImpl = "@property " ~ (S[$-1]).stringof ~ " 
property" ~ to!string(S.length) ~ "();\n";

}
else
{
		enum GettersImpl = "@property " ~ (S[$-1]).stringof ~ " 
property" ~ to!string(S.length) ~ "();\n"

   ~ GettersImpl!(S[0..$-1]);
}
}


interface A(S...)
{
mixin Getters!S;
}

class B : A!(int, long, string)
{
//if everything works, we get errors here for missing methods.
}


Re: creating a variadic interface

2013-07-08 Thread JS

On Monday, 8 July 2013 at 10:16:22 UTC, John Colvin wrote:

On Monday, 8 July 2013 at 09:34:46 UTC, JS wrote:


this may seem a bit nonsensical but it is just an example:

interface A(T, S...)
{
  ... Generate a getter for each type in S...
  // e.g., @property S[0] property1();
  //   @property S[1] property2();
  // 
}

I imagine I have to use a mixin template but I'm unsure how to 
create a static loop that can be used properly.


I think maybe using mixin's of mixin's is possible but I can't 
think of any simple way. Any ideas?


Here you go :)

//just to hide the string mixin.
mixin template Getters(S ...)
{
mixin(GettersImpl!S);
}

import std.conv : to;
template GettersImpl(S ...)
{
static if(S.length == 0)
{
enum GettersImpl = "";
}
else static if(S.length == 1)
{
		enum GettersImpl = "@property " ~ (S[$-1]).stringof ~ " 
property" ~ to!string(S.length) ~ "();\n";

}
else
{
		enum GettersImpl = "@property " ~ (S[$-1]).stringof ~ " 
property" ~ to!string(S.length) ~ "();\n"

   ~ GettersImpl!(S[0..$-1]);
}
}


interface A(S...)
{
mixin Getters!S;
}

class B : A!(int, long, string)
{
//if everything works, we get errors here for missing methods.
}




I guess you beat me too it but I came up with something very 
similar which I think works too(uses foreach instead of 
recursion)..



mixin template a(T...)
{
template b(TT...)
{
static string eval()
{
string s;
int i = 0;
foreach(t; TT)
s = "@property "~(t).stringof~" 
Name"~to!string(i++)~"();\n";
return s;
}
enum b = eval();
}

mixin("mixin(b!T);");

}


Re: creating a variadic interface

2013-07-08 Thread Artur Skawina
On 07/08/13 13:25, JS wrote:
> mixin template a(T...)
> {
> template b(TT...)
> {
> static string eval()
> {
> string s;
> int i = 0;
> foreach(t; TT)
> s = "@property "~(t).stringof~" Name"~to!string(i++)~"();\n";
> return s;
> }
> enum b = eval();
> }
> 
> mixin("mixin(b!T);");
> 
> }

It won't work if one of the types isn't already available inside the
template - the .stringof will give you the name, but the mixin
will fail; to avoid this you can use `T[0]` etc as the type directly,
w/o stringifying.

Something like this would also work:

   template evalExpMap(string C, string F, A...) {
  enum evalExpMap = {
 import std.array, std.conv;
 string s, l;
 static if (is(typeof(A))) alias B = typeof(A);
else   alias B = A;
 foreach (I, _; B) {
auto r = replace( replace(F, "%s", A[I].stringof),
 "%d", to!string(I));
l ~= (I?", ":"") ~ r;
s ~=   r ~ ";\n";
 }
 return replace(replace(C, "%...;", s), "%...", l);
  }();
   }

   interface A(T, S...) {
  mixin(evalExpMap!(q{%...;}, q{@property S[%d]/*%s*/ property%d()}, S));
   }

   class C : A!(int, long, string) { /* Needs `propertyN` implementations. */ }


It expands to:

   interface A(T, S...) {   
  @property S[0]/*long*/ property0();
  @property S[1]/*string*/ property1();
   }

and is more readable (once one knows what that helper does ;) ).

In real code, the property names may need to be more configurable;
but I'm not sure what you want to use this for. The helper rewrites
every "%s" pattern -> type-name and every "%d" -> index; maybe that
is enough.

artur


Re: creating a variadic interface

2013-07-08 Thread John Colvin

On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote:
It won't work if one of the types isn't already available 
inside the

template - the .stringof will give you the name, but the mixin
will fail;


When would the type not be available?


Re: creating a variadic interface

2013-07-08 Thread Artur Skawina
On 07/08/13 15:12, John Colvin wrote:
> On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote:
>> It won't work if one of the types isn't already available inside the
>> template - the .stringof will give you the name, but the mixin
>> will fail;
> 
> When would the type not be available?
> 

   auto as() { struct An {} return An(); }
   template A(T) {}

   A!(typeof(as()))

T.stringof inside 'A' will return a name, but there's no way to map
it back to a type.
The 'A' template can be instantiated from a different module - the type
won't be available in A if A doesn't import that other module.
The type may be private, then even an import in A (or any parent scope)
won't help.

artur 


Re: creating a variadic interface

2013-07-08 Thread John Colvin

On Monday, 8 July 2013 at 13:42:36 UTC, Artur Skawina wrote:

On 07/08/13 15:12, John Colvin wrote:

On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote:
It won't work if one of the types isn't already available 
inside the

template - the .stringof will give you the name, but the mixin
will fail;


When would the type not be available?



   auto as() { struct An {} return An(); }
   template A(T) {}

   A!(typeof(as()))

T.stringof inside 'A' will return a name, but there's no way to 
map

it back to a type.
The 'A' template can be instantiated from a different module - 
the type

won't be available in A if A doesn't import that other module.
The type may be private, then even an import in A (or any 
parent scope)

won't help.

artur


Ah ok, I see.

In those cases you're not going to be able to declare a function 
that explicitly uses that type anyway, whether handwritten or 
generated as above.


Re: creating a variadic interface

2013-07-08 Thread Artur Skawina
On 07/08/13 16:12, John Colvin wrote:
> On Monday, 8 July 2013 at 13:42:36 UTC, Artur Skawina wrote:
>> On 07/08/13 15:12, John Colvin wrote:
>>> On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote:
 It won't work if one of the types isn't already available inside the
 template - the .stringof will give you the name, but the mixin
 will fail;
>>>
>>> When would the type not be available?
>>>
>>
>>auto as() { struct An {} return An(); }
>>template A(T) {}
>>
>>A!(typeof(as()))
>>
>> T.stringof inside 'A' will return a name, but there's no way to map
>> it back to a type.
>> The 'A' template can be instantiated from a different module - the type
>> won't be available in A if A doesn't import that other module.
>> The type may be private, then even an import in A (or any parent scope)
>> won't help.
> 
> Ah ok, I see.
> 
> In those cases you're not going to be able to declare a function that 
> explicitly uses that type anyway, whether handwritten or generated as above.

   struct A(T) { T f(T a) { return a.blah; } }

artur


Re: creating a variadic interface

2013-07-08 Thread John Colvin

On Monday, 8 July 2013 at 14:25:17 UTC, Artur Skawina wrote:

On 07/08/13 16:12, John Colvin wrote:

On Monday, 8 July 2013 at 13:42:36 UTC, Artur Skawina wrote:

On 07/08/13 15:12, John Colvin wrote:

On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote:
It won't work if one of the types isn't already available 
inside the
template - the .stringof will give you the name, but the 
mixin

will fail;


When would the type not be available?



   auto as() { struct An {} return An(); }
   template A(T) {}

   A!(typeof(as()))

T.stringof inside 'A' will return a name, but there's no way 
to map

it back to a type.
The 'A' template can be instantiated from a different module 
- the type

won't be available in A if A doesn't import that other module.
The type may be private, then even an import in A (or any 
parent scope)

won't help.


Ah ok, I see.

In those cases you're not going to be able to declare a 
function that explicitly uses that type anyway, whether 
handwritten or generated as above.


   struct A(T) { T f(T a) { return a.blah; } }

artur


Right So the problem is that there's no mapping available
between the type name and the type, not that the type itself is
unavailable for use. Don't know why I'm being so slow with this
today...must be the heat!