digitalmars.D.learn - Deduplicating template reflection code
- Johannes Pfau (22/22) Apr 14 2017 I've got this code duplicated in quite some functions:
- Stefan Koch (4/30) Apr 14 2017 The Idiomatic way would be to wrap it inside another template.
- Moritz Maxeiner (40/51) Apr 14 2017 Your options are at least the following two (both untested, but
- Johannes Pfau (12/40) Apr 14 2017 I'd prefer the first approach, simply to avoid string mixins. I think
- Moritz Maxeiner (42/49) Apr 14 2017 Sure, but that's a bit more complex:
- Johannes Pfau (5/65) Apr 14 2017 Great, thanks that's exactly the solution I wanted. Figuring this out by
- Moritz Maxeiner (5/11) Apr 14 2017 No problem, I often enough encounter instances of
I've got this code duplicated in quite some functions:
---------------------
foreach (member; __traits(derivedMembers, API))
{
// Guards against private members
static if (__traits(compiles, __traits(getMember, API, member)))
{
static if (isSomeFunction!(__traits(getMember, API, member))
&& !hasUDA!(__traits(getMember, API, member), IgnoreUDA)
&& !isSpecialFunction!member)
{
alias overloads = MemberFunctionsTuple!(API, member);
foreach (MethodType; overloads)
{
// function dependent code here
}
}
}
}
--------------------
What's the idiomatic way to refactor / reuse this code fragment?
-- Johannes
Apr 14 2017
On Friday, 14 April 2017 at 08:24:00 UTC, Johannes Pfau wrote:
I've got this code duplicated in quite some functions:
---------------------
foreach (member; __traits(derivedMembers, API))
{
// Guards against private members
static if (__traits(compiles, __traits(getMember, API,
member)))
{
static if (isSomeFunction!(__traits(getMember, API,
member))
&& !hasUDA!(__traits(getMember, API, member),
IgnoreUDA)
&& !isSpecialFunction!member)
{
alias overloads = MemberFunctionsTuple!(API,
member);
foreach (MethodType; overloads)
{
// function dependent code here
}
}
}
}
--------------------
What's the idiomatic way to refactor / reuse this code fragment?
-- Johannes
The Idiomatic way would be to wrap it inside another template.
In a year or so you won't need to worry about template overhead
anymore, (if I succeed that is :) )
Apr 14 2017
On Friday, 14 April 2017 at 08:24:00 UTC, Johannes Pfau wrote:
I've got this code duplicated in quite some functions:
---------------------
[...]1
foreach (MethodType; overloads)
{
// function dependent code here
}
[...]2
--------------------
What's the idiomatic way to refactor / reuse this code fragment?
-- Johannes
Your options are at least the following two (both untested, but
should work):
Option 1: Template Mixins
---
mixin template Foo(alias API, Dg)
{
void foo()
{
[...]1
foreach (MethodType; overloads)
{
Dg(MethodType);
}
[...]2
}
}
mixin Foo!(API, (MethodType) {
// function dependent code here
});
foo();
---
Option 2: Code generation using CTFE
---
string genFoo(alias API, string justDoIt)
{
import std.array : appender;
auto code = appender!string;
code.put(`[...]1`);
code.put(`foreach (MethodType; overloads) {`);
code.put(justDoIt);
code put(`}`);
code.put(`[...]2`);
}
mixin(genFoo!(API, q{
// function dependent code here
})());
---
Personally, I'd consider the second approach to be idiomatic, but
YMMW.
Apr 14 2017
Am Fri, 14 Apr 2017 08:55:48 +0000
schrieb Moritz Maxeiner <moritz ucworks.org>:
mixin Foo!(API, (MethodType) {
// function dependent code here
});
foo();
---
Option 2: Code generation using CTFE
---
string genFoo(alias API, string justDoIt)
{
import std.array : appender;
auto code = appender!string;
code.put(`[...]1`);
code.put(`foreach (MethodType; overloads) {`);
code.put(justDoIt);
code put(`}`);
code.put(`[...]2`);
}
mixin(genFoo!(API, q{
// function dependent code here
})());
---
Personally, I'd consider the second approach to be idiomatic, but
YMMW.
I'd prefer the first approach, simply to avoid string mixins. I think
these can often get ugly ;-)
Is there some way to wrap the 'type selection'? In pseudo-code something
like this:
enum FilteredOverloads(API) = ...
foreach(Overload, FilteredOverloads!API)
{
....
}
-- Johannes
Apr 14 2017
On Friday, 14 April 2017 at 11:29:03 UTC, Johannes Pfau wrote:
Is there some way to wrap the 'type selection'? In pseudo-code
something like this:
enum FilteredOverloads(API) = ...
foreach(Overload, FilteredOverloads!API)
{
....
}
Sure, but that's a bit more complex:
---
[...] // IgnoreUDA declaration
[...] // isSpecialFunction declaration
///
template FilteredOverloads(API)
{
import std.traits : hasUDA, isSomeFunction,
MemberFunctionsTuple;
import std.meta : staticMap;
import std.typetuple : TypeTuple;
enum derivedMembers = __traits(derivedMembers, API);
template MemberOverloads(string member)
{
static if (__traits(compiles, __traits(getMember, API,
member)))
{
static if (isSomeFunction!(__traits(getMember, API,
member))
&& !hasUDA!(__traits(getMember, API,
member), IgnoreUDA)
&& !isSpecialFunction!member) {
alias MemberOverloads =
MemberFunctionsTuple!(API, member);
} else {
alias MemberOverloads = TypeTuple!();
}
} else {
alias MemberOverloads = TypeTuple!();
}
}
alias FilteredOverloads = staticMap!(MemberOverloads,
derivedMembers);
}
//pragma(msg, FilteredOverloads!API);
foreach(Overload; FilteredOverloads!API) {
// function dependent code here
}
---
Nested templates and std.meta are your best friends if this is
the solution you prefer :)
Apr 14 2017
Am Fri, 14 Apr 2017 13:41:45 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>:On Friday, 14 April 2017 at 11:29:03 UTC, Johannes Pfau wrote:Great, thanks that's exactly the solution I wanted. Figuring this out by myself is a bit above my template skill level ;-) -- JohannesIs there some way to wrap the 'type selection'? In pseudo-code something like this: enum FilteredOverloads(API) = ... foreach(Overload, FilteredOverloads!API) { .... }Sure, but that's a bit more complex: --- [...] // IgnoreUDA declaration [...] // isSpecialFunction declaration /// template FilteredOverloads(API) { import std.traits : hasUDA, isSomeFunction, MemberFunctionsTuple; import std.meta : staticMap; import std.typetuple : TypeTuple; enum derivedMembers = __traits(derivedMembers, API); template MemberOverloads(string member) { static if (__traits(compiles, __traits(getMember, API, member))) { static if (isSomeFunction!(__traits(getMember, API, member)) && !hasUDA!(__traits(getMember, API, member), IgnoreUDA) && !isSpecialFunction!member) { alias MemberOverloads = MemberFunctionsTuple!(API, member); } else { alias MemberOverloads = TypeTuple!(); } } else { alias MemberOverloads = TypeTuple!(); } } alias FilteredOverloads = staticMap!(MemberOverloads, derivedMembers); } //pragma(msg, FilteredOverloads!API); foreach(Overload; FilteredOverloads!API) { // function dependent code here } --- Nested templates and std.meta are your best friends if this is the solution you prefer :)
Apr 14 2017
On Friday, 14 April 2017 at 17:57:49 UTC, Johannes Pfau wrote:Am Fri, 14 Apr 2017 13:41:45 +0000 schrieb Moritz Maxeiner <moritz ucworks.org>:No problem, I often enough encounter instances of <strikethrough>THE DAMNED COMPILER JUST NOT DOING WHAT I WANT</strikethrough> being frustrated with templates myself. Usually looking at phobos code helps, though.[...]Great, thanks that's exactly the solution I wanted. Figuring this out by myself is a bit above my template skill level ;-) -- Johannes
Apr 14 2017









Stefan Koch <uplink.coder googlemail.com> 