www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP 57: static foreach

reply Timon Gehr <timon.gehr gmx.ch> writes:
http://wiki.dlang.org/DIP57/

Thoughts?
Mar 09 2014
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/09/2014 10:31 PM, Timon Gehr wrote:
 http://wiki.dlang.org/DIP57/

 Thoughts?
broken link. http://wiki.dlang.org/DIP57
Mar 09 2014
next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/9/14, Timon Gehr <timon.gehr gmx.ch> wrote:
 On 03/09/2014 10:31 PM, Timon Gehr wrote:
 http://wiki.dlang.org/DIP57/

 Thoughts?
broken link. http://wiki.dlang.org/DIP57
Off-topic but this isn't the first time I ended up at the wrong page due to trailing "/". Can we fix this for the DWiki?
Mar 09 2014
parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Sunday, 9 March 2014 at 21:46:59 UTC, Andrej Mitrovic wrote:
 On 3/9/14, Timon Gehr <timon.gehr gmx.ch> wrote:
 On 03/09/2014 10:31 PM, Timon Gehr wrote:
 http://wiki.dlang.org/DIP57/

 Thoughts?
broken link. http://wiki.dlang.org/DIP57
Off-topic but this isn't the first time I ended up at the wrong page due to trailing "/". Can we fix this for the DWiki?
I could add an Apache rewrite rule to strip trailing slashes. I've done something similar for unbalanced parens, since trailing closing parens are usually not considered as a part of URL by URL-matching algorithms. An alternative approach is to just create a redirect page. I've heard these are cheap, as far as database resources are concerned.
Mar 09 2014
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Timon Gehr:

 http://wiki.dlang.org/DIP57
 With these semantics, tuple foreach, eg:
 
 void main(){
     foreach(x;Seq!(1,2)){ ... }
 }
 
 is equivalent to static foreach with an additional pair of 
 curly brackets, eg:
 
 void main(){
     static foreach(x;Seq!(1,2)){ { ... } }
 }
Having three kinds of foreach in a language is too much. So I suggest to add to DIP57 one more thing: that the introduction of static foreach should come with a warning against the usage of not-static foreach on tuples (and eventually this warning should become a deprecation message). Bye, bearophile
Mar 09 2014
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sunday, 9 March 2014 at 21:47:17 UTC, bearophile wrote:
 suggest to add to DIP57 one more thing: that the introduction 
 of static foreach should come with a warning against the usage 
 of not-static foreach on tuples (and eventually this warning 
 should become a deprecation message).
I don't agree because foreach on a tuple is just plain foreach. That it unrolls is just an implementation detail that doesn't change much else. I think considering it to be a separate kind of loop is like considering foreach over arrays, ranges, and opApply items separate loops. Those are just different implementation details of the same user concept.
Mar 09 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 I don't agree because foreach on a tuple is just plain foreach. 
 That it unrolls is just an implementation detail that doesn't 
 change much else.
How can it be an implementation detail if the compiler accepts code like this? You can't do anything like this with a dynamic foreach, it must to be unrolled at compile-time: import std.typetuple, std.string; void main() { foreach (x; TypeTuple!(0, 1, 2)) { mixin(format("int x%d;", x)); } } Bye, bearophile
Mar 09 2014
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sunday, 9 March 2014 at 23:14:06 UTC, bearophile wrote:
 How can it be an implementation detail if the compiler accepts 
 code like this?
That's really just a CTFE limitation, not an entirely different kind of loop. If ctfe carried across just a little bit more, this could work too: foreach(immutable a; [1,2,3]) mixin(a); The major, fundamental difference between static foreach as proposed and foreach is: * static foreach does not introduce a new scope. If you take your code and try to access x0 outside the loop, it will fail. With a static foreach, that would be allowed (just like how static if can declare variables) * static foreach would be valid at module level and inside templates (like static if), whereas regular foreach is only permitted in a function (like regular if).
 You can't do anything like this with a dynamic foreach, it must 
 to be unrolled at compile-time:
Note that the optimizer is allowed to unroll any loop it desires. You can have local variables in a regular runtime loop too, but you can't refer to them outside, so the unrolling here is a code generator implementation detail rather than a fundamental difference in the language.
Mar 09 2014
parent "bearophile" <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 Note that the optimizer is allowed to unroll any loop it 
 desires. You can have local variables in a regular runtime loop 
 too, but you can't refer to them outside, so the unrolling here 
 is a code generator implementation detail rather than a 
 fundamental difference in the language.
OK. So if this DIP gets accepted I will close down my issue 4085, because it's obsolete. All your extra explanations could be useful for future (probable) questions in D.learn. Bye, bearophile
Mar 09 2014
prev sibling parent "Dicebot" <public dicebot.lv> writes:
On Sunday, 9 March 2014 at 21:53:45 UTC, Adam D. Ruppe wrote:
 On Sunday, 9 March 2014 at 21:47:17 UTC, bearophile wrote:
 suggest to add to DIP57 one more thing: that the introduction 
 of static foreach should come with a warning against the usage 
 of not-static foreach on tuples (and eventually this warning 
 should become a deprecation message).
I don't agree because foreach on a tuple is just plain foreach. That it unrolls is just an implementation detail that doesn't change much else. I think considering it to be a separate kind of loop is like considering foreach over arrays, ranges, and opApply items separate loops. Those are just different implementation details of the same user concept.
Can't agree. You can't call it implementation detail if it is a property that leaks into user code and can be relied upon. I sometimes hear statements akin to "tuple is like container and tuple foreach is just like foreach" but it is a very idealistic view that simply does not match current D state. Despite all behavior hacks that try to make it look so. So right now it _is_ a separate and distinctive kind of loop. At the same time it is a very specialized tool and deprecating it does not sound like a practical approach for reducing language complexity. Probably some years later if we eventually find out no one uses it anymore.
Mar 10 2014
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 9 March 2014 at 21:31:40 UTC, Timon Gehr wrote:
 http://wiki.dlang.org/DIP57/

 Thoughts?
I like it.
Mar 09 2014
prev sibling next sibling parent reply Kenji Hara <k.hara.pg gmail.com> writes:
2014-03-10 6:31 GMT+09:00 Timon Gehr <timon.gehr gmx.ch>:

 http://wiki.dlang.org/DIP57

 Thoughts?
From the "Semantics" section:
 For static foreach statements, break and continue are supported and
treated like for foreach statements over tuples. This is questionable sentence. On the foreach with tuple iteration, break and continue have no effect for the unrolling. void main() { import std.typetuple, std.stdio; foreach (i; TypeTuple!(1, 2, 3)) { static if (i == 2) continue; else static if (i == 3) break; pragma(msg, "CT: i = ", i); // prints 1, 2, and 3 in CT writeln("RT: i = ", i); // prints only 1 in RT } } So, I think that static foreach *cannot* support break and continue as same as foreach with tuples. Kenji Hara
Mar 09 2014
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/10/2014 07:40 AM, Kenji Hara wrote:
 2014-03-10 6:31 GMT+09:00 Timon Gehr <timon.gehr gmx.ch
 <mailto:timon.gehr gmx.ch>>:

     http://wiki.dlang.org/DIP57 <http://wiki.dlang.org/DIP57/>

     Thoughts?


  From the "Semantics" section:

  > For static foreach statements, break and continue are supported and
 treated like for foreach statements over tuples.

 This is questionable sentence. On the foreach with tuple iteration,
 break and continue have no effect for the unrolling.
 ...
That's what is meant, and indeed this is visible in the examples section.
 void main()
 {
      import std.typetuple, std.stdio;

      foreach (i; TypeTuple!(1, 2, 3))
      {
          static if (i == 2) continue;
          else static if (i == 3) break;

          pragma(msg, "CT: i = ", i); // prints 1, 2, and 3 in CT
          writeln("RT: i = ", i);     // prints only 1 in RT
      }
 }

 So, I think that static foreach *cannot* support break and continue as
 same as foreach with tuples.

 Kenji Hara
Yes it can. What is your suggestion? Influencing the unrolling?
Mar 10 2014
prev sibling parent reply Shammah Chancellor <shammah.chancellor gmail.com> writes:
On Monday, 10 March 2014 at 06:40:49 UTC, Kenji Hara wrote:
 2014-03-10 6:31 GMT+09:00 Timon Gehr <timon.gehr gmx.ch>:

 http://wiki.dlang.org/DIP57

 Thoughts?
From the "Semantics" section:
 For static foreach statements, break and continue are 
 supported and
treated like for foreach statements over tuples. This is questionable sentence. On the foreach with tuple iteration, break and continue have no effect for the unrolling. void main() { import std.typetuple, std.stdio; foreach (i; TypeTuple!(1, 2, 3)) { static if (i == 2) continue; else static if (i == 3) break; pragma(msg, "CT: i = ", i); // prints 1, 2, and 3 in CT writeln("RT: i = ", i); // prints only 1 in RT } } So, I think that static foreach *cannot* support break and continue as same as foreach with tuples. Kenji Hara
Ditto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy. -Shammah
Nov 03 2015
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/03/2015 03:12 PM, Shammah Chancellor wrote:

 Ditto.  This needs `static continue` and `static break`.  Without this
 functionality, the control flow in `static foreach` becomes very unwieldy.
"continue" and "break" (no static) should just work. -- Andrei
Nov 03 2015
parent reply Idan Arye <GenericNPC gmail.com> writes:
On Tuesday, 3 November 2015 at 20:28:43 UTC, Andrei Alexandrescu 
wrote:
 On 11/03/2015 03:12 PM, Shammah Chancellor wrote:

 Ditto.  This needs `static continue` and `static break`.  
 Without this
 functionality, the control flow in `static foreach` becomes 
 very unwieldy.
"continue" and "break" (no static) should just work. -- Andrei
Depending on what you want `continue` and `break` to do. Consider this: http://dpaste.dzfl.pl/925e4aec6173 Note that the pragma gets compiled for `true` even though we `continue` before it. This is the expected behavior from `continue`, but a `static continue` should have skipped that, and a static break should have skipped the compilation of the rest of the AliasSeq.
Nov 04 2015
parent krzaq <dlangmailinglist krzaq.cc> writes:
On Wednesday, 4 November 2015 at 11:41:59 UTC, Idan Arye wrote:
 On Tuesday, 3 November 2015 at 20:28:43 UTC, Andrei 
 Alexandrescu wrote:
 On 11/03/2015 03:12 PM, Shammah Chancellor wrote:

 Ditto.  This needs `static continue` and `static break`.  
 Without this
 functionality, the control flow in `static foreach` becomes 
 very unwieldy.
"continue" and "break" (no static) should just work. -- Andrei
Depending on what you want `continue` and `break` to do. Consider this: http://dpaste.dzfl.pl/925e4aec6173 Note that the pragma gets compiled for `true` even though we `continue` before it. This is the expected behavior from `continue`, but a `static continue` should have skipped that, and a static break should have skipped the compilation of the rest of the AliasSeq.
From a D newbie's point of view this is very far from the expected behaviour.
Nov 04 2015
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/3/15 3:12 PM, Shammah Chancellor wrote:
 On Monday, 10 March 2014 at 06:40:49 UTC, Kenji Hara wrote:
 2014-03-10 6:31 GMT+09:00 Timon Gehr <timon.gehr gmx.ch>:

 http://wiki.dlang.org/DIP57

 Thoughts?
 From the "Semantics" section:
 For static foreach statements, break and continue are supported and
treated like for foreach statements over tuples. This is questionable sentence. On the foreach with tuple iteration, break and continue have no effect for the unrolling. void main() { import std.typetuple, std.stdio; foreach (i; TypeTuple!(1, 2, 3)) { static if (i == 2) continue; else static if (i == 3) break; pragma(msg, "CT: i = ", i); // prints 1, 2, and 3 in CT writeln("RT: i = ", i); // prints only 1 in RT } } So, I think that static foreach *cannot* support break and continue as same as foreach with tuples. Kenji Hara
Ditto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy.
There's no reason technical or otherwise to require "static" with continue/break in static foreach. -- Andrei
Nov 03 2015
parent Shammah Chancellor <shammah.chancellor gmail.com> writes:
On Wednesday, 4 November 2015 at 00:23:59 UTC, Andrei 
Alexandrescu wrote:
 On 11/3/15 3:12 PM, Shammah Chancellor wrote:
 So, I think that static foreach *cannot* support break and 
 continue as
 same as foreach with tuples.

 Kenji Hara
Ditto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy.
There's no reason technical or otherwise to require "static" with continue/break in static foreach. -- Andrei
I'm not sure that I agree with you. However, in the latest DMD it appears that named break/continues work with foreach over tuples now. So, I'll rescind my statement regarding separating compile-time control flow vs runtime control flow. -Shammah
Nov 03 2015
prev sibling next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Sunday, 9 March 2014 at 21:31:40 UTC, Timon Gehr wrote:
 http://wiki.dlang.org/DIP57/

 Thoughts?
1)
 Additionally, CTFE is invoked on all expressions occurring in 
 the ForeachAggregate
I think it can be phrased more universally "ForeachTypeList symbols must be evaluated as compile-time entities, if it is not possible, implementation-defined compilation error happens". 2) Saying that it does not introduce a new scope is not entirely true as symbols from ForeachTypeList should not be available outside of static foreach. You mention it later in the same block but it is important concept to define as we currently don't have such pseudo-scopes (do we?) 3)
 The body of the static foreach statement or static foreach 
 declaration is duplicated once for each iteration which the 
 corresponding foreach statement with an empty body would 
 perform when executed in CTFE
I don't understand the reason behind limiting static foreach to CTFE semantics. Simply evaluating and pasting the body for each iteration should be enough. It is much closer to mixin template instances in that regard. This will also remove necessity to rely on shadowing rules to re-define ForeachTypeList symbols as at the time of pasting the body those won't exist anymore. 4)
  Declarations introduced in the body itself are inserted into 
 this enclosing scope
Isn't "enclosing" term used only for scope-to-scope relations or it is applicable to any language construct? (I don't know) 5)
 For static foreach statements, break and continue are supported 
 and treated like for foreach statements over tuples.
It is impossible as far as I understand existing semantics. Currently placed continue/break refer to created scope and don't stop iteration over remaining template argument list members. This is not applicable to generic foreach. 6) In "Iterating over members of a scope" example there is a strange Python-like colon after `static if` condition. Typo? :) 7) In "Relation to tuple foreach" stating equivalency is not correct. It is more of subset and even not a strict one as semantics will differ in some corner cases. For example, iterating over expression list will create a local copy right now if `ref` is not used. I'd really want this to not be the case for static foreach. Overall provided examples seem to much my expectations but semantics description can be more structured and detailed.
Mar 10 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/10/2014 02:08 PM, Dicebot wrote:
 On Sunday, 9 March 2014 at 21:31:40 UTC, Timon Gehr wrote:
 http://wiki.dlang.org/DIP57/

 Thoughts?
1)
 Additionally, CTFE is invoked on all expressions occurring in the
 ForeachAggregate
I think it can be phrased more universally "ForeachTypeList symbols must be evaluated as compile-time entities, if it is not possible, implementation-defined compilation error happens". ...
I don't see how this is more universal.
 2) Saying that it does not introduce a new scope is not entirely true as
 symbols from ForeachTypeList should not be available outside of static
 foreach. You mention it later in the same block but it is important
 concept to define as we currently don't have such pseudo-scopes
 ...
The description only says that the usual scope for foreach statements is not introduced.
 (do we?)
 ...
Nope.
 3)
 The body of the static foreach statement or static foreach declaration
 is duplicated once for each iteration which the corresponding foreach
 statement with an empty body would perform when executed in CTFE
I don't understand the reason behind limiting static foreach to CTFE semantics. Simply evaluating and pasting the body for each iteration should be enough. It is much closer to mixin template instances in that regard. ...
I don't understand how the DIP is 'limiting static foreach to CTFE semantics' and/or why this is a bad thing or how your suggestion is different.
 This will also remove necessity to rely on shadowing rules to re-define
 ForeachTypeList symbols as at the time of pasting the body those won't
 exist anymore.
 ...
I have no idea what this means.
 4)

  Declarations introduced in the body itself are inserted into this
 enclosing scope
Isn't "enclosing" term used only for scope-to-scope relations or it is applicable to any language construct? (I don't know) ...
There is no formal language spec. What is meant is the scope `hosting' the static foreach construct.
 5)

 For static foreach statements, break and continue are supported and
 treated like for foreach statements over tuples.
It is impossible as far as I understand existing semantics. Currently placed continue/break refer to created scope and don't stop iteration over remaining template argument list members. This is not applicable to generic foreach. ...
This is not 'impossible', it is trivial to implement. Is your point that you would prefer break and continue to affect static foreach expansion?
 6)

 In "Iterating over members of a scope" example there is a strange
 Python-like colon after `static if` condition. Typo? :)
 ...
Nope. This is a language feature. See: http://dlang.org/version.html
 7)

 In "Relation to tuple foreach" stating equivalency is not correct.
I have removed the section.
 It is more of subset and even not a strict one as semantics will differ in
 some corner cases.
I think as described they would not need to.
 For example, iterating over expression list will
 create a local copy right now if `ref` is not used. I'd really want this
 to not be the case for static foreach.
 ...
I think the description is actually not detailed enough to warrant this critique. (In particular, it is not clear what 'ref' should do.) I.e., I think currently the following code is ambiguous: int y,z; static foreach(x;Seq!(y,z)) x = 2; // what is the value of y and z now?
 Overall provided examples seem to much my expectations but semantics
 description can be more structured and detailed.
Agreed. I will do another iteration when I can find the time. Maybe I will have to re-specify the behaviour of foreach though.
Mar 10 2014
parent "Dicebot" <public dicebot.lv> writes:
On Monday, 10 March 2014 at 15:38:09 UTC, Timon Gehr wrote:
 I think it can be phrased more universally "ForeachTypeList 
 symbols must
 be evaluated as compile-time entities, if it is not possible,
 implementation-defined compilation error happens".
 ...
I don't see how this is more universal.
CTFE stands for "Compile-Time Function Evaluation". When you don't have functions or expressions (i.e. pure type list) referring to it looks very confusing to me and I start guessing if you mean some specific CTFE semantics I don't know about or it is just a wording for "accessible during compile-time". Also spec does not say that const-folding happens via CTFE as a rule, thus you are exposing implementation details that way. Looks like your intentions here are same as mine but exact phrasing creates misunderstanding :)
 5)

 For static foreach statements, break and continue are 
 supported and
 treated like for foreach statements over tuples.
It is impossible as far as I understand existing semantics. Currently placed continue/break refer to created scope and don't stop iteration over remaining template argument list members. This is not applicable to generic foreach. ...
This is not 'impossible', it is trivial to implement. Is your point that you would prefer break and continue to affect static foreach expansion?
Impossible in a sense that those are not applicable in declaration context. Also break/continue do look weird in absence of scope, I don't like it. Would prefer those to either affect static foreach expansion or refer to outer loop (compilation error if there is none).
 6)

 In "Iterating over members of a scope" example there is a 
 strange
 Python-like colon after `static if` condition. Typo? :)
 ...
Nope. This is a language feature. See: http://dlang.org/version.html
What a horrible creation! :O It is first time I see such static if syntax in actual D code. Why was it introduced?
 I think the description is actually not detailed enough to 
 warrant this critique. (In particular, it is not clear what 
 'ref' should do.)

 I.e., I think currently the following code is ambiguous:

 int y,z;
 static foreach(x;Seq!(y,z)) x = 2;
 // what is the value of y and z now?
With existing foreach y and z will remain int.init If you change it to be `foreach(ref x; Seq..`, y and z will change to 2. For static foreach I want it to be 2 and `ref x` rejected at compilation time as nonsense.
Mar 11 2014
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/10/14, Kenji Hara <k.hara.pg gmail.com> wrote:
 This is questionable sentence. On the foreach with tuple iteration, break
 and continue have no effect for the unrolling.
Whatever is implemented, we need to make sure the current code is possible. in std.conv.to: ----- switch(value) { foreach (I, member; NoDuplicates!(EnumMembers!S)) { case member: return to!T(enumRep!(immutable(T), S, I)); } default: } -----
Mar 10 2014
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Timon Geh:

 http://wiki.dlang.org/DIP57/

 Thoughts?
Is it good to support this syntax too? static foreach (enum i; 0 .. 10) {} Bye, bearophile
Mar 26 2014
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/26/2014 01:33 PM, bearophile wrote:
 Timon Geh:

 http://wiki.dlang.org/DIP57/

 Thoughts?
Is it good to support this syntax too? static foreach (enum i; 0 .. 10) {} Bye, bearophile
Yes, I think so. I'll try to finish the DIP this weekend.
Mar 26 2014
parent reply Daniel N <ufo orbiting.us> writes:
On Wednesday, 26 March 2014 at 22:14:44 UTC, Timon Gehr wrote:
 On 03/26/2014 01:33 PM, bearophile wrote:
 Timon Geh:

 http://wiki.dlang.org/DIP57/

 Thoughts?
Is it good to support this syntax too? static foreach (enum i; 0 .. 10) {} Bye, bearophile
Yes, I think so. I'll try to finish the DIP this weekend.
template DIP(Args...) { static foreach(alias a ; Args) { } } Would supporting 'alias' conflate too much into one DIP?
Nov 03 2015
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/04/2015 12:39 AM, Daniel N wrote:
 On Wednesday, 26 March 2014 at 22:14:44 UTC, Timon Gehr wrote:
 On 03/26/2014 01:33 PM, bearophile wrote:
 Timon Geh:

 http://wiki.dlang.org/DIP57/

 Thoughts?
Is it good to support this syntax too? static foreach (enum i; 0 .. 10) {} Bye, bearophile
Yes, I think so. I'll try to finish the DIP this weekend.
template DIP(Args...) { static foreach(alias a ; Args) { } } Would supporting 'alias' conflate too much into one DIP?
The DIP would allow: template DIP(Args...){ static foreach(a;Args){} } This has the semantics you want. This is identical to the existing Seq-foreach: auto foo(Args...)(){ foreach(a;Args){ pragma(msg,a.stringof); } } void main(){ foo!(1,"2",main,int)(); } In this sense, the syntax seems redundant, but if it is introduced, it should also be allowed for Seq-foreach. (I think this should also be the case for enum loop variabes as proposed by bearophile.) I have updated the DIP draft according to those considerations, but I'm not sure whether 'alias' should be kept or not. (Also, probably, using 'alias' or 'enum' on a loop variable for a non-seq foreach should automatically turn it into a seq foreach, but I'm not sure this is within the scope of the DIP.)
Nov 03 2015
parent Daniel N <ufo orbiting.us> writes:
On Wednesday, 4 November 2015 at 00:17:25 UTC, Timon Gehr wrote:
 This is identical to the existing Seq-foreach:

 auto foo(Args...)(){
     foreach(a;Args){
         pragma(msg,a.stringof);
     }
 }

 void main(){
     foo!(1,"2",main,int)();
 }
It comes very close... but this breaks down(see below). If it had been a real alias, it would have worked, but then again it can't always be lowered to an alias in the general case, since alias has it's own quirks. Hmm, I guess the real solution is to fix the quirks of alias in a separate DIP, first after that foreach could be changed take advantage of it? auto foo(Args...)(){ foreach(a;Args){ pragma(msg, a.stringof); } } auto bar(Args...)(){ foreach(const i, _;Args){ alias arg = Args[i]; pragma(msg, arg.stringof); } } void main(){ int a,b,c; foo!(a,b,c)(); bar!(a,b,c)(); foo!(1)(); // bar!(1)(); }
Nov 03 2015