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? -- JohannesThe 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? -- JohannesYour 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