www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - creating a variadic interface

reply "JS" <js.mdnq gmail.com> writes:
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?
Jul 08 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
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. }
Jul 08 2013
parent reply "JS" <js.mdnq gmail.com> writes:
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);"); }
Jul 08 2013
parent reply Artur Skawina <art.08.09 gmail.com> writes:
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
Jul 08 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
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?
Jul 08 2013
parent reply Artur Skawina <art.08.09 gmail.com> writes:
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
Jul 08 2013
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
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.
Jul 08 2013
parent reply Artur Skawina <art.08.09 gmail.com> writes:
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
Jul 08 2013
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
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!
Jul 08 2013