digitalmars.D - most non-function templates could be advantageously replaced by
- Timothee Cour (80/80) May 13 2013 Phobos has a number of *non-function template* traits (std.traits,
- Dicebot (9/10) May 14 2013 My conclusion as well. Currently I follow simple rule when doing
- Jonathan M Davis (18/30) May 14 2013 I believe that the typical approach at this point is that if it's someth...
- Steven Schveighoffer (9/20) May 14 2013 Another is that CTFE can hit a brick wall and fail to compile. It's an ...
Phobos has a number of *non-function template* traits (std.traits, std.typetuple etc), eg: ---- in std.traits: template hasMember(T, string name) { static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface)) enum bool hasMember = staticIndexOf!(name, __traits(allMembers, T)) != -1 || __traits(compiles, { mixin("alias Identity!(T."~name~") Sym;"); }); else enum bool hasMember = false; } ---- I see those *disadvantages* with non-function templates: * syntax is less clear than regular function templates (there's no way to tell the return type without looking at the code or using some convention relating to the template name) * they're not DRY, as the template name is typically repeated (maybe in multiple places) inside the template body (hasMember appears 3 times here) * behavior of templates is actually weird, for example: ---- template A1(T){enum A1=0;} template A2(T){enum B=0;} template A3(T){enum A3=0;enum B=0;} void main(){ enum a1=A1!int; //ok enum a2=A2!int.B; //ok // enum a3=A3!int.B; //Error: no property 'B' for type 'int' } ---- Maybe this was for historical reasons (ie CTFE might've come after those design patterns were invented). I would propose to use *regular template functions* instead, whenever possible (essentially for the ones that return a value): For our example, this would become: ---- bool hasMember(T, string name)(){ static if (is(T == struct) || is(T == class) || is(T == union) || is(T = = interface)) return staticIndexOf!(name, __traits(allMembers, T)) != -1 || __traits(compiles, { mixin("alias Identity!(T."~name~") Sym; "); }); else return false; } // can be used in exactly the same way: static assert(hasMember!(A,"field")); ---- *Advantages*: * clear syntax: returns bool, and body is simpler to read as well * DRY: hasMember only mentioned once * no weird behavior as above * doesn't break any code as usage is the same (backwards compatible) In fact, I was able to convert with no problems a number of other such templates: staticIndexOf isSame expectType genericIndexOf etc... For the latter (genericIndexOf), the template body contained a clause like that: enum next = genericIndexOf!(e, tail).index; enum index = (next == -1) ? -1 : 1 + next; during conversion, I just had to add the line: return Tuple!(int, "index",int, "next")(index,next); which could further be simplified using a helper function as its a common idiom, into: return TupleNamed!("index","next")(index,next); *Limitations*: One typical case where this isn't possible is when a template defines an type alias, eg: ---- template Iota(int stop) { static if (stop <= 0) alias Iota=TypeTuple!(); else alias Iota=TypeTuple!(Iota!(stop-1), stop-1); } ----
May 13 2013
On Tuesday, 14 May 2013 at 06:56:23 UTC, Timothee Cour wrote:...My conclusion as well. Currently I follow simple rule when doing meta-programming in D: * If stuff returns type, make it a template and write in functional recursive flavor * If stuff returns data, make it a function (template function if needed) and just let CTFE do the magic. One major advantage is that it helps to reduce template instance count and thus compiler memory consumption.
May 14 2013
On Tuesday, May 14, 2013 10:27:38 Dicebot wrote:On Tuesday, 14 May 2013 at 06:56:23 UTC, Timothee Cour wrote:I believe that the typical approach at this point is that if it's something that will only ever be done at compile time and/or is querying about a type, an eponymous template is used, whereas if it's something that might be useful at runtime, then a normal function is used which is then CTFEable. I've never really thought about making the type stuff into functions, but I don't really agree that it's a problem that they aren't, particularly since it makes no sense to use them at runtime, and at least with eponymous templates, even if you try and use them at runtime, the result is still calculated at compile time, unlike with CTFE. I'm not sure that it actually matters much, but that _would_ result in a slight performance penalty for any code that was using traits in runtime code for some reason (though again, I don't know why you would), and as Steven pointed out, CTFE carries a definite performance penalty at compile time at the moment (though hopefully that's temporary). My gut reaction is definitely to keep doing traits as we have been, and it does seem off to me to make it so that something that's purely meant for compile time can be used at runtime, but it may make sense to change them. - Jonathan M Davis...My conclusion as well. Currently I follow simple rule when doing meta-programming in D: * If stuff returns type, make it a template and write in functional recursive flavor * If stuff returns data, make it a function (template function if needed) and just let CTFE do the magic. One major advantage is that it helps to reduce template instance count and thus compiler memory consumption.
May 14 2013
On Tue, 14 May 2013 02:56:09 -0400, Timothee Cour <thelastmammoth gmail.com> wrote:*Limitations*: One typical case where this isn't possible is when a template defines an type alias, eg: ---- template Iota(int stop) { static if (stop <= 0) alias Iota=TypeTuple!(); else alias Iota=TypeTuple!(Iota!(stop-1), stop-1); } ----Another is that CTFE can hit a brick wall and fail to compile. It's an implementation bug, but something to consider before changing everything to CTFE. AFAIK, straight templates don't have this limitation. There was quite a bit of talk at the conference about how CTFE is awesome, but too limited based on the current D front end. Otherwise, I like the idea. If nothing else, it gives more flexibility. -Steve
May 14 2013