digitalmars.D.learn - creating a variadic interface
- JS (12/12) Jul 08 2013 this may seem a bit nonsensical but it is just an example:
- John Colvin (34/46) Jul 08 2013 Here you go :)
- JS (21/71) Jul 08 2013 I guess you beat me too it but I came up with something very
- Artur Skawina (36/54) Jul 08 2013 It won't work if one of the types isn't already available inside the
- John Colvin (2/6) Jul 08 2013 When would the type not be available?
- Artur Skawina (11/18) Jul 08 2013 auto as() { struct An {} return An(); }
- John Colvin (5/27) Jul 08 2013 Ah ok, I see.
- Artur Skawina (3/28) Jul 08 2013 struct A(T) { T f(T a) { return a.blah; } }
- John Colvin (5/40) Jul 08 2013 Right.... So the problem is that there's no mapping available
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
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
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: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);"); }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
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
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
On 07/08/13 15:12, John Colvin wrote:On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote: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. arturIt 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
On Monday, 8 July 2013 at 13:42:36 UTC, Artur Skawina wrote:On 07/08/13 15:12, John Colvin wrote: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.On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote: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. arturIt 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
On 07/08/13 16:12, John Colvin wrote:On Monday, 8 July 2013 at 13:42:36 UTC, Artur Skawina wrote:struct A(T) { T f(T a) { return a.blah; } } arturOn 07/08/13 15:12, John Colvin wrote: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.On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote: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.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
On Monday, 8 July 2013 at 14:25:17 UTC, Artur Skawina wrote:On 07/08/13 16:12, John Colvin wrote: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!On Monday, 8 July 2013 at 13:42:36 UTC, Artur Skawina wrote:struct A(T) { T f(T a) { return a.blah; } } arturOn 07/08/13 15:12, John Colvin wrote: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.On Monday, 8 July 2013 at 13:01:32 UTC, Artur Skawina wrote: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.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