digitalmars.D - Recursive template expansion
- Norbert Nemec (45/45) Mar 01 2010 Hi there,
- Philippe Sigaud (27/30) Mar 01 2010 I don't know. Using factory functions, it seems to work and it has the n...
- Norbert Nemec (7/58) Mar 01 2010 Thanks, Philippe, for the elegant workaround!
- Philippe Sigaud (12/17) Mar 01 2010 De nada. I vaguely remembered being confronted by this one, but didn't k...
- Robert Jacques (5/16) Mar 01 2010 On Mon, 01 Mar 2010 12:47:49 -0500, Philippe Sigaud
- Robert Jacques (20/65) Mar 01 2010 Well, first and foremost you should file the missing line number bug in ...
Hi there, trying out a few ideas on expression templates, I stumbled over the following problem, for which I cannot find a solution. The code below demonstrates what I try to do: I need to construct a nested template type at compile time. Any expression should correspond to an equivalent nested tree of templates which can then be unraveled at compile time. For some reason, the D compiler complains about a "recursive template expansion" as soon as I use ((a+b)+c). My guess is that this is supposed to protect against infinite recursions at compile time. In this case, however, there is actually no risk of that. Nested types are only needed at the depth of nested expressions that actually occur. Is there any fundamental error in my thinking? Some simple misunderstanding? Some slightly different syntax to be used? Or is it simply an unnessessary restriction in the compiler that could easily be removed? Apart from all that, I want to point out that the error message does not even give a line number in the code. If any such error occurs within a larger piece of software, identifying the problem would be a nightmare! Greetings, Norbert --------------- import std.stdio; struct sum(A,B) { A a; B b; auto opAdd(T)(T a) { return .sum!(sum,T)(this,a); } } struct base { auto opAdd(T)(T a) { return .sum!(base,T)(this,a); } } void main() { base a,b,c; // first a few working examples writeln(typeid(a)); // base writeln(typeid(a+b)); // sum!(base,base).sum writeln(typeid(a+(b+c))); // sum!(base,sum!(base,base)).sum sum!(sum!(base,base),base) d; writeln(typeid(d)); // sum!(sum!(base,base),base).sum // the following produces // Error: recursive template expansion for // template argument sum!(base,base) writeln(typeid((a+b)+c)); // sum!(sum!(base,base),base).sum } ---------------
Mar 01 2010
On Mon, Mar 1, 2010 at 10:16, Norbert Nemec <Norbert nemec-online.de> wrote:Is there any fundamental error in my thinking? Some simple misunderstanding? Some slightly different syntax to be used? Or is it simply an unnessessary restriction in the compiler that could easily be removed?I don't know. Using factory functions, it seems to work and it has the nice side-effect of simplfying the syntax (templated functions do all the type deducing): import std.stdio; struct Sum(A,B) { A a; B b; auto opAdd(T)(T a) { return sum(this,a); } } struct Base { auto opAdd(T)(T a) { return sum(this,a); } } Sum!(A,B) sum(A,B)(A a, B b) { return Sum!(A,B)(a,b);} Base!(A,B) base(A,B)(A a, B b) { return Base!(A,B)(a,b);} void main() { Base a,b,c; auto d = a+b; writeln(typeof(e).stringof); // Sum!(Base, Base) auto e =de+a; writeln(typeof(f).stringof); // Sum!(Sum!(Base, Base),Base) auto f = e+e+d; // Look Ma, no parenthesis writeln(typeof(g).stringof); // Sum!(Sum!(Sum!(Sum!(Base,Base),Base), Sum!(Sum!(Base,Base),Base)),Sum!(Base,Base)) } Cheers, Philippe
Mar 01 2010
Thanks, Philippe, for the elegant workaround! Still I would like to know the reason for my original failure, especially since the compiler error message did not contain any line number whatsoever. Getting this kind of error message in a large project must be really ugly to solve, even if the workaround is so straightforward... Philippe Sigaud wrote:On Mon, Mar 1, 2010 at 10:16, Norbert Nemec <Norbert nemec-online.de <mailto:Norbert nemec-online.de>> wrote: Is there any fundamental error in my thinking? Some simple misunderstanding? Some slightly different syntax to be used? Or is it simply an unnessessary restriction in the compiler that could easily be removed? I don't know. Using factory functions, it seems to work and it has the nice side-effect of simplfying the syntax (templated functions do all the type deducing):import std.stdio; struct Sum(A,B) { A a; B b; auto opAdd(T)(T a) { return sum(this,a); } } struct Base { auto opAdd(T)(T a) { return sum(this,a); } } Sum!(A,B) sum(A,B)(A a, B b) { return Sum!(A,B)(a,b);} Base!(A,B) base(A,B)(A a, B b) { return Base!(A,B)(a,b);} void main() { Base a,b,c; auto d = a+b; writeln(typeof(e).stringof); // Sum!(Base, Base) auto e =de+a; writeln(typeof(f).stringof); // Sum!(Sum!(Base, Base),Base) auto f = e+e+d; // Look Ma, no parenthesis writeln(typeof(g).stringof); // Sum!(Sum!(Sum!(Sum!(Base,Base),Base), Sum!(Sum!(Base,Base),Base)),Sum!(Base,Base)) } Cheers, Philippe
Mar 01 2010
On Mon, Mar 1, 2010 at 17:26, Norbert Nemec <Norbert nemec-online.de> wrote:Thanks, Philippe, for the elegant workaround!De nada. I vaguely remembered being confronted by this one, but didn't know it was a bug (my code wasn't as clear as yours). I now realize that my coding in D is a least partially made of such tricks.Still I would like to know the reason for my original failure, especially since the compiler error message did not contain any line number whatsoever. Getting this kind of error message in a large project must be really ugly to solve, even if the workaround is so straightforward...What bugs (!) me is that a+(b+c) didn't create an error, whereas (a+b)+c did... I first tried to define opAdd_r so that the compiler could try c.opAdd_r((a+b)), but to no avail... As for the line numbers, yes it's hard and it's reason enough to put this on bugzilla. Maybe even as 2 different tickets. I remember having other incomplete error messages some days ago. I should strive to note them and put them on puremagic. Philippe
Mar 01 2010
On Mon, 01 Mar 2010 12:47:49 -0500, Philippe Sigaud <philippe.sigaud gmail.com> wrote: [snip]Well, it makes sense. a+(b+c) is base.op_Add(sum), which is okay. And opApp will always be tried before opAdd_r, and so DMD fails.Still I would like to know the reason for my original failure, especially since the compiler error message did not contain any line number whatsoever. Getting this kind of error message in a large project must be really ugly to solve, even if the workaround is so straightforward...What bugs (!) me is that a+(b+c) didn't create an error, whereas (a+b)+c did... I first tried to define opAdd_r so that the compiler could try c.opAdd_r((a+b)), but to no avail...
Mar 01 2010
On Mon, 01 Mar 2010 04:16:41 -0500, Norbert Nemec <Norbert nemec-online.de> wrote:Hi there, trying out a few ideas on expression templates, I stumbled over the following problem, for which I cannot find a solution. The code below demonstrates what I try to do: I need to construct a nested template type at compile time. Any expression should correspond to an equivalent nested tree of templates which can then be unraveled at compile time. For some reason, the D compiler complains about a "recursive template expansion" as soon as I use ((a+b)+c). My guess is that this is supposed to protect against infinite recursions at compile time. In this case, however, there is actually no risk of that. Nested types are only needed at the depth of nested expressions that actually occur. Is there any fundamental error in my thinking? Some simple misunderstanding? Some slightly different syntax to be used? Or is it simply an unnessessary restriction in the compiler that could easily be removed? Apart from all that, I want to point out that the error message does not even give a line number in the code. If any such error occurs within a larger piece of software, identifying the problem would be a nightmare! Greetings, Norbert --------------- import std.stdio; struct sum(A,B) { A a; B b; auto opAdd(T)(T a) { return .sum!(sum,T)(this,a); } } struct base { auto opAdd(T)(T a) { return .sum!(base,T)(this,a); } } void main() { base a,b,c; // first a few working examples writeln(typeid(a)); // base writeln(typeid(a+b)); // sum!(base,base).sum writeln(typeid(a+(b+c))); // sum!(base,sum!(base,base)).sum sum!(sum!(base,base),base) d; writeln(typeid(d)); // sum!(sum!(base,base),base).sum // the following produces // Error: recursive template expansion for // template argument sum!(base,base) writeln(typeid((a+b)+c)); // sum!(sum!(base,base),base).sum } ---------------Well, first and foremost you should file the missing line number bug in bugzilla. As for the RTE itself, logically it shouldn't happen with this, but here are some work arounds. 1) Alter the type signature with a dummy var struct sum(A,B,bool FLAG = false) { A a; B b; auto opAdd(T)(T a) { return sum!(sum!(A,B,!FLAG),T)(this,a); } } 2) use a typedef struct sum(A,B) { A a; B b; private typedef sum __sum; auto opAdd(T)(T a) { return sum!(__sum,T)(this,a); } } 3) You could also switch to using a generic expression template. i.e. op(string expression, string nextVar, T...) {}
Mar 01 2010