digitalmars.D - DIP 57: static foreach
- Timon Gehr (2/2) Mar 09 2014 http://wiki.dlang.org/DIP57/
- Timon Gehr (3/5) Mar 09 2014 broken link.
- Andrej Mitrovic (3/9) Mar 09 2014 Off-topic but this isn't the first time I ended up at the wrong page
- Vladimir Panteleev (7/19) Mar 09 2014 I could add an Apache rewrite rule to strip trailing slashes.
- bearophile (8/21) Mar 09 2014 Having three kinds of foreach in a language is too much. So I
- Adam D. Ruppe (7/11) Mar 09 2014 I don't agree because foreach on a tuple is just plain foreach.
- bearophile (12/15) Mar 09 2014 How can it be an implementation detail if the compiler accepts
- Adam D. Ruppe (20/24) Mar 09 2014 That's really just a CTFE limitation, not an entirely different
- bearophile (6/11) Mar 09 2014 OK. So if this DIP gets accepted I will close down my issue 4085,
- Dicebot (12/23) Mar 10 2014 Can't agree. You can't call it implementation detail if it is a
- deadalnix (2/4) Mar 09 2014 I like it.
- Kenji Hara (18/22) Mar 09 2014 treated like for foreach statements over tuples.
- Timon Gehr (3/27) Mar 10 2014 Yes it can. What is your suggestion? Influencing the unrolling?
- Shammah Chancellor (5/30) Nov 03 2015 Ditto. This needs `static continue` and `static break`. Without
- Andrei Alexandrescu (2/5) Nov 03 2015 "continue" and "break" (no static) should just work. -- Andrei
- Idan Arye (9/17) Nov 04 2015 Depending on what you want `continue` and `break` to do. Consider
- krzaq (3/21) Nov 04 2015 From a D newbie's point of view this is very far from the
- Andrei Alexandrescu (3/39) Nov 03 2015 There's no reason technical or otherwise to require "static" with
- Shammah Chancellor (7/21) Nov 03 2015 I'm not sure that I agree with you. However, in the latest DMD
- Dicebot (38/50) Mar 10 2014 I think it can be phrased more universally "ForeachTypeList
- Timon Gehr (25/84) Mar 10 2014 The description only says that the usual scope for foreach statements is...
- Dicebot (22/60) Mar 11 2014 CTFE stands for "Compile-Time Function Evaluation". When you
- Andrej Mitrovic (14/16) Mar 10 2014 Whatever is implemented, we need to make sure the current code is
- bearophile (5/7) Mar 26 2014 Is it good to support this syntax too?
- Timon Gehr (3/11) Mar 26 2014 Yes, I think so.
- Daniel N (8/23) Nov 03 2015 template DIP(Args...)
- Timon Gehr (23/48) Nov 03 2015 The DIP would allow:
- Daniel N (26/35) Nov 03 2015 It comes very close... but this breaks down(see below). If it had
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
On 3/9/14, Timon Gehr <timon.gehr gmx.ch> wrote:On 03/09/2014 10:31 PM, Timon Gehr wrote: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?http://wiki.dlang.org/DIP57/ Thoughts?broken link. http://wiki.dlang.org/DIP57
Mar 09 2014
On Sunday, 9 March 2014 at 21:46:59 UTC, Andrej Mitrovic wrote:On 3/9/14, Timon Gehr <timon.gehr gmx.ch> wrote: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.On 03/09/2014 10:31 PM, Timon Gehr wrote: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?http://wiki.dlang.org/DIP57/ Thoughts?broken link. http://wiki.dlang.org/DIP57
Mar 09 2014
Timon Gehr:http://wiki.dlang.org/DIP57With 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
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
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
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
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
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: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.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 10 2014
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
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 andtreated 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
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 HaraYes it can. What is your suggestion? Influencing the unrolling?
Mar 10 2014
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>:Ditto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy. -Shammahhttp://wiki.dlang.org/DIP57 Thoughts?From the "Semantics" section:For static foreach statements, break and continue are supported andtreated 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
Nov 03 2015
On 11/03/2015 03:12 PM, Shammah Chancellor wrote:"continue" and "break" (no static) should just work. -- AndreiDitto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy.
Nov 03 2015
On Tuesday, 3 November 2015 at 20:28:43 UTC, Andrei Alexandrescu wrote:On 11/03/2015 03:12 PM, Shammah Chancellor wrote: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."continue" and "break" (no static) should just work. -- AndreiDitto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy.
Nov 04 2015
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:From a D newbie's point of view this is very far from the expected behaviour.On 11/03/2015 03:12 PM, Shammah Chancellor wrote: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."continue" and "break" (no static) should just work. -- AndreiDitto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy.
Nov 04 2015
On 11/3/15 3:12 PM, Shammah Chancellor wrote:On Monday, 10 March 2014 at 06:40:49 UTC, Kenji Hara wrote:There's no reason technical or otherwise to require "static" with continue/break in static foreach. -- Andrei2014-03-10 6:31 GMT+09:00 Timon Gehr <timon.gehr gmx.ch>:Ditto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy.http://wiki.dlang.org/DIP57 Thoughts?From the "Semantics" section:For static foreach statements, break and continue are supported andtreated 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
Nov 03 2015
On Wednesday, 4 November 2015 at 00:23:59 UTC, Andrei Alexandrescu wrote:On 11/3/15 3:12 PM, Shammah Chancellor wrote: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. -ShammahThere's no reason technical or otherwise to require "static" with continue/break in static foreach. -- AndreiSo, I think that static foreach *cannot* support break and continue as same as foreach with tuples. Kenji HaraDitto. This needs `static continue` and `static break`. Without this functionality, the control flow in `static foreach` becomes very unwieldy.
Nov 03 2015
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 ForeachAggregateI 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 CTFEI 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 scopeIsn'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
On 03/10/2014 02:08 PM, Dicebot wrote:On Sunday, 9 March 2014 at 21:31:40 UTC, Timon Gehr wrote:I don't see how this is more universal.http://wiki.dlang.org/DIP57/ Thoughts?1)Additionally, CTFE is invoked on all expressions occurring in the ForeachAggregateI 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 ...The description only says that the usual scope for foreach statements is not introduced.(do we?) ...Nope.3)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.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 CTFEI 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. ...I have no idea what this means.4)There is no formal language spec. What is meant is the scope `hosting' the static foreach construct.Declarations introduced in the body itself are inserted into this enclosing scopeIsn't "enclosing" term used only for scope-to-scope relations or it is applicable to any language construct? (I don't know) ...5)This is not 'impossible', it is trivial to implement. Is your point that you would prefer break and continue to affect static foreach expansion?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? :) ...Nope. This is a language feature. See: http://dlang.org/version.html7) 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
On Monday, 10 March 2014 at 15:38:09 UTC, Timon Gehr wrote: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 :)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.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).5)This is not 'impossible', it is trivial to implement. Is your point that you would prefer break and continue to affect static foreach expansion?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. ...What a horrible creation! :O It is first time I see such static if syntax in actual D code. Why was it introduced?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.htmlI 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
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
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
On 03/26/2014 01:33 PM, bearophile wrote:Timon Geh:Yes, I think so. I'll try to finish the DIP this weekend.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
On Wednesday, 26 March 2014 at 22:14:44 UTC, Timon Gehr wrote:On 03/26/2014 01:33 PM, bearophile wrote:template DIP(Args...) { static foreach(alias a ; Args) { } } Would supporting 'alias' conflate too much into one DIP?Timon Geh:Yes, I think so. I'll try to finish the DIP this weekend.http://wiki.dlang.org/DIP57/ Thoughts?Is it good to support this syntax too? static foreach (enum i; 0 .. 10) {} Bye, bearophile
Nov 03 2015
On 11/04/2015 12:39 AM, Daniel N wrote:On Wednesday, 26 March 2014 at 22:14:44 UTC, Timon Gehr wrote: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.)On 03/26/2014 01:33 PM, bearophile wrote:template DIP(Args...) { static foreach(alias a ; Args) { } } Would supporting 'alias' conflate too much into one DIP?Timon Geh:Yes, I think so. I'll try to finish the DIP this weekend.http://wiki.dlang.org/DIP57/ Thoughts?Is it good to support this syntax too? static foreach (enum i; 0 .. 10) {} Bye, bearophile
Nov 03 2015
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