Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
July 08, 2013 creating a variadic interface | ||||
---|---|---|---|---|
| ||||
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? |
July 08, 2013 Re: creating a variadic interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | 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.
}
|
July 08, 2013 Re: creating a variadic interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | 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);");
}
|
July 08, 2013 Re: creating a variadic interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | 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
|
July 08, 2013 Re: creating a variadic interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | 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?
|
July 08, 2013 Re: creating a variadic interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | 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
|
July 08, 2013 Re: creating a variadic interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | 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.
|
July 08, 2013 Re: creating a variadic interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | 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
|
July 08, 2013 Re: creating a variadic interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | 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!
|
Copyright © 1999-2021 by the D Language Foundation