digitalmars.D - DIP 1010--Static foreach--Formal Review
- Mike Parker (9/9) Jul 10 2017 As promised, since there has been zero feedback on DIP 1010, "Static
- jmh530 (16/27) Jul 10 2017 I have two somewhat related questions.
- Timon Gehr (6/40) Jul 11 2017 No. (They are static structs because they are static structs in
- jmh530 (18/21) Jul 11 2017 Clearly, this has more power than inout.
- Steven Schveighoffer (21/41) Jul 11 2017 It's not as good actually. In the mutable form, you can modify the data.
- jmh530 (4/6) Jul 11 2017 [snip]
- Daniel N (2/13) Jul 11 2017 how is __local handled with nested static foreach?
- Timon Gehr (26/41) Jul 12 2017 The following code works:
- Jack Stouffer (3/4) Jul 11 2017 Sorry for not getting in on the original review, but I've
- Steven Schveighoffer (40/53) Jul 11 2017 A few things:
- H. S. Teoh via Digitalmars-d (10/15) Jul 11 2017 This is a false impression. It actually does not break from the loop,
- Steven Schveighoffer (28/42) Jul 11 2017 Yes, I know that it still generates all the code, but the break is still...
- John Colvin (4/55) Jul 12 2017 break inside a case inside a static foreach inside a switch is an
- Timon Gehr (13/77) Jul 12 2017 foreach(enum i; 0..3) does not currently compile and is not proposed in
- Steven Schveighoffer (33/70) Jul 12 2017 It's in the DIP, regardless of whether it's critical to the acceptance
- Adrian Matoga (4/7) Jul 12 2017 I'd also vote for gradual removal of foreach over a tuple. It
- Mike Parker (4/11) Jul 13 2017 Thanks for all the feedback. I don't see anything that is a
As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process. So, if you have any thoughts on the DIP, now is the time to express them. Thanks! https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.md
Jul 10 2017
On Monday, 10 July 2017 at 08:53:42 UTC, Mike Parker wrote:As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process. So, if you have any thoughts on the DIP, now is the time to express them. Thanks! https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.mdI have two somewhat related questions. In the "Generating fields" section, does it have to be a static struct? I see another example with an abstract class with a static for each, but I don't see simpler struct/class examples. I ask this because it seems like static foreach can be used to provide the same functionality as inout, e.g. class Foo { static foreach(T; AliasSeq!(int,const(int),immutable(int))) { void bar(T t) { } } }
Jul 10 2017
On 10.07.2017 20:07, jmh530 wrote:On Monday, 10 July 2017 at 08:53:42 UTC, Mike Parker wrote:No. (They are static structs because they are static structs in Vladimir's code.)As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process. So, if you have any thoughts on the DIP, now is the time to express them. Thanks! https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.mdI have two somewhat related questions. In the "Generating fields" section, does it have to be a static struct?I see another example with an abstract class with a static for each, but I don't see simpler struct/class examples. I ask this because it seems like static foreach can be used to provide the same functionality as inout, e.g. class Foo { static foreach(T; AliasSeq!(int,const(int),immutable(int))) { void bar(T t) { } } }Yes, this code works and does what you want. (The difference to inout is that you actually get three different implementations and you are able to vary the implementation based on T.)
Jul 11 2017
On Tuesday, 11 July 2017 at 07:42:22 UTC, Timon Gehr wrote:Yes, this code works and does what you want. (The difference to inout is that you actually get three different implementations and you are able to vary the implementation based on T.)Clearly, this has more power than inout. I suppose what I'm wondering if it makes inout superfluous. For instance, we should be able to add something like template Inout(T) { alias Inout = AliasSeq(T, const(T), immutable(T)); } and use static foreach on it to replicate one of inouts most useful features. The other major use of inout is something like class Foo { void bar(int t) inout { } } which I imagine could be replaced now with SetFunctionAttributes, though my method was a little ugly and I don't know if there's a more elegant approach with static foreach.
Jul 11 2017
On 7/11/17 10:08 AM, jmh530 wrote:On Tuesday, 11 July 2017 at 07:42:22 UTC, Timon Gehr wrote:It's not as good actually. In the mutable form, you can modify the data. It all depends on if you care about const guarantees or bloat. If you don't and just want to handle all forms, you can use a template (much easier IMO than using static foreach).Yes, this code works and does what you want. (The difference to inout is that you actually get three different implementations and you are able to vary the implementation based on T.)Clearly, this has more power than inout.I suppose what I'm wondering if it makes inout superfluous.I would say no, inout has a very well defined and convenient mechanism to deal with properties on all const flavors of objects. There are many who say templates are good enough, so YMMV. However, nothing so far has successfully implemented the requirement that during the inout function execution, the compiler enforces no mutability.The other major use of inout is something like class Foo { void bar(int t) inouthm..., this should probably return inout for it to make sense.{ } } which I imagine could be replaced now with SetFunctionAttributes, though my method was a little ugly and I don't know if there's a more elegant approach with static foreach.There is a way to do it with 'this' template parameter: int * member; auto bar(this T)() { return member; // returns const, immutable, or mutable depending on modifier for 'this' } Still is bloated into multiple instantiations, and still allowed to mutate for mutable call. Plus it's confusing. -Steve
Jul 11 2017
On Tuesday, 11 July 2017 at 14:23:27 UTC, Steven Schveighoffer wrote:It's not as good actually. In the mutable form, you can modify the data.[snip] Clears things up. Thanks.
Jul 11 2017
On Monday, 10 July 2017 at 08:53:42 UTC, Mike Parker wrote:As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process. So, if you have any thoughts on the DIP, now is the time to express them. Thanks! https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.mdhow is __local handled with nested static foreach?
Jul 11 2017
On 11.07.2017 09:50, Daniel N wrote:On Monday, 10 July 2017 at 08:53:42 UTC, Mike Parker wrote:The following code works: --- static foreach(i;0..4){ static if(i) __local alias outerPrevious = __previous; static foreach(j;0..4){ static if(i&&j){ pragma(msg, outerPrevious.i," ",__previous.j); } } } --- It prints: --- 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 --- (However, note that DIP 1010 does not propose adding __local to the language.)As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process. So, if you have any thoughts on the DIP, now is the time to express them. Thanks! https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.mdhow is __local handled with nested static foreach?
Jul 12 2017
On Monday, 10 July 2017 at 08:53:42 UTC, Mike Parker wrote:https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.mdSorry for not getting in on the original review, but I've submitted a PR for the DIP in regards to formatting.
Jul 11 2017
On 7/10/17 4:53 AM, Mike Parker wrote:As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process. So, if you have any thoughts on the DIP, now is the time to express them. Thanks! https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.mdA few things: 1. I can't wait for this to get in. I'm anticipating success :) 2. I see no point in having foreach(enum i; 0.. 3) when static foreach(i; 0 .. 3) works just fine? 3. The only controversial part I see is that `break` doesn't break from the foreach loop. While I agree with the reasoning, and support that concept, the truth is we currently have a "poor man's" static foreach using a foreach over a tuple, and that DOES break from the loop. For instance: size_t idx; switch(someval) { case something: foreach(v; AliasSeq!(1, 2, 3)) { if(shouldBreak(v)) break; // today, this jumps to moreProcessing() line } moreProcessing(); break; } If I replaced foreach with static foreach(v; 1 .. 4), it now breaks out of the switch? As much as I would rather see the proposed behavior, I feel it's too confusing given the existing foreach behavior. I think in this case, you have to require a break label. A possible deprecation path: 1. In the case where "static foreach" is inside another construct that allows breaking, require a break label. However, foreach over a tuple would continue to exhibit today's behavior. 2. print warning message for foreach over a tuple that contains a break without a label. Warn users that a future version will not allow breaking from the foreach. 3. disallow breaking out of the foreach directly (i.e. jumping to the closing brace of the loop), even if there is a label (you can surround foreach with a do{} while(false) if you need this behavior). 4. Remove the requirement for labeling. Both static foreach and foreach on a tuple do not break from the loop construct. -Steve
Jul 11 2017
On Tue, Jul 11, 2017 at 07:18:51PM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...]3. The only controversial part I see is that `break` doesn't break from the foreach loop. While I agree with the reasoning, and support that concept, the truth is we currently have a "poor man's" static foreach using a foreach over a tuple, and that DOES break from the loop.This is a false impression. It actually does not break from the loop, but inserts a break in the generated code, and continues to unroll the rest of the loop. It's only at codegen that the subsequent iterations are detected as dead code and elided. See: https://wiki.dlang.org/User T -- Любишь кататься - люби и саночки возить.
Jul 11 2017
On 7/11/17 7:21 PM, H. S. Teoh via Digitalmars-d wrote:On Tue, Jul 11, 2017 at 07:18:51PM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...]Yes, I know that it still generates all the code, but the break is still interpreted as breaking out of the loop. Timon's proposal says it "does not interact with break", so I interpret that as meaning it should break out of whatever construct is surrounding the loop, not the loop itself. Currently this: foreach(j; 0 .. 2) foreach(i; AliasSeq!(0, 1)) { writeln(i); static if(i == 0) break; } will print 0 0 Whereas with my understanding, this: foreach(j; 0 .. 2) static foreach(i; 0 .. 2) { writeln(i); static if(i == 0) break; } would print 0 This seems too confusing. -Steve3. The only controversial part I see is that `break` doesn't break from the foreach loop. While I agree with the reasoning, and support that concept, the truth is we currently have a "poor man's" static foreach using a foreach over a tuple, and that DOES break from the loop.This is a false impression. It actually does not break from the loop, but inserts a break in the generated code, and continues to unroll the rest of the loop. It's only at codegen that the subsequent iterations are detected as dead code and elided. See: https://wiki.dlang.org/User
Jul 11 2017
On Tuesday, 11 July 2017 at 23:50:26 UTC, Steven Schveighoffer wrote:On 7/11/17 7:21 PM, H. S. Teoh via Digitalmars-d wrote:break inside a case inside a static foreach inside a switch is an interesting case for this sort of reasoningOn Tue, Jul 11, 2017 at 07:18:51PM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...]Yes, I know that it still generates all the code, but the break is still interpreted as breaking out of the loop. Timon's proposal says it "does not interact with break", so I interpret that as meaning it should break out of whatever construct is surrounding the loop, not the loop itself. Currently this: foreach(j; 0 .. 2) foreach(i; AliasSeq!(0, 1)) { writeln(i); static if(i == 0) break; } will print 0 0 Whereas with my understanding, this: foreach(j; 0 .. 2) static foreach(i; 0 .. 2) { writeln(i); static if(i == 0) break; } would print 0 This seems too confusing. -Steve3. The only controversial part I see is that `break` doesn't break from the foreach loop. While I agree with the reasoning, and support that concept, the truth is we currently have a "poor man's" static foreach using a foreach over a tuple, and that DOES break from the loop.This is a false impression. It actually does not break from the loop, but inserts a break in the generated code, and continues to unroll the rest of the loop. It's only at codegen that the subsequent iterations are detected as dead code and elided. See: https://wiki.dlang.org/User
Jul 12 2017
On 12.07.2017 01:18, Steven Schveighoffer wrote:On 7/10/17 4:53 AM, Mike Parker wrote:foreach(enum i; 0..3) does not currently compile and is not proposed in this DIP, but it would be useful for the case where you need an unrolled foreach loop.As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process. So, if you have any thoughts on the DIP, now is the time to express them. Thanks! https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.mdA few things: 1. I can't wait for this to get in. I'm anticipating success :) 2. I see no point in having foreach(enum i; 0.. 3) when static foreach(i; 0 .. 3) works just fine? ...3. The only controversial part I see is that `break` doesn't break from the foreach loop. While I agree with the reasoning, and support that concept, the truth is we currently have a "poor man's" static foreach using a foreach over a tuple, and that DOES break from the loop. For instance: size_t idx; switch(someval) { case something: foreach(v; AliasSeq!(1, 2, 3)) { if(shouldBreak(v)) break; // today, this jumps to moreProcessing() line } moreProcessing(); break; } If I replaced foreach with static foreach(v; 1 .. 4), it now breaks out of the switch? ...Yes.As much as I would rather see the proposed behavior, I feel it's too confusing given the existing foreach behavior. I think in this case, you have to require a break label. A possible deprecation path: 1. In the case where "static foreach" is inside another construct that allows breaking, require a break label. However, foreach over a tuple would continue to exhibit today's behavior. 2. print warning message for foreach over a tuple that contains a break without a label. Warn users that a future version will not allow breaking from the foreach. 3. disallow breaking out of the foreach directly (i.e. jumping to the closing brace of the loop), even if there is a label (you can surround foreach with a do{} while(false) if you need this behavior). 4. Remove the requirement for labeling. Both static foreach and foreach on a tuple do not break from the loop construct. -SteveI don't see why for foreach, break behaviour should depend on the aggregate, that is much more confusing. static foreach is not a loop with a loop body, it generates multiple versions of the given code. There is no reason why static foreach and foreach should have "the same" (whatever that even means!) behaviour with respect to runtime break, and if it is really considered too confusing, static foreach should just always require an explicit label. (But this is painful for me to implement, as it is unnatural.)
Jul 12 2017
On 7/12/17 4:23 AM, Timon Gehr wrote:On 12.07.2017 01:18, Steven Schveighoffer wrote:It's in the DIP, regardless of whether it's critical to the acceptance of the DIP. As it's something on the table for W&A to look at, I wanted to voice my opinion on it.On 7/10/17 4:53 AM, Mike Parker wrote:foreach(enum i; 0..3) does not currently compile and is not proposed in this DIP, but it would be useful for the case where you need an unrolled foreach loop.As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process. So, if you have any thoughts on the DIP, now is the time to express them. Thanks! https://github.com/dlang/DIPs/blob/master/DIPs/DIP1010.mdA few things: 1. I can't wait for this to get in. I'm anticipating success :) 2. I see no point in having foreach(enum i; 0.. 3) when static foreach(i; 0 .. 3) works just fine? ...I don't see why for foreach, break behaviour should depend on the aggregate, that is much more confusing.Perhaps. My point of view is that I'm generally using foreach over a tuple to generate switch cases. I always think that the break is going to apply to the switch statement, and it gets me every time. In fact, in writing this post, I just found a (harmless?) bug in my code: switch(str) { foreach(n; names) { case n: ... break; } default: break; } It's harmless because the default case does nothing. But it certainly isn't what I should have written! I think of foreach over a tuple as separate from foreach over a runtime type. To me, it's already a different syntax and more akin to static foreach. One may argue that static foreach looks just like foreach, and so all of them should behave the same.static foreach is not a loop with a loop body, it generates multiple versions of the given code. There is no reason why static foreach and foreach should have "the same" (whatever that even means!) behaviour with respect to runtime break, and if it is really considered too confusing, static foreach should just always require an explicit label. (But this is painful for me to implement, as it is unnatural.)From a user perspective, whether I reach for one tool or the other, the behavior shouldn't be subtly different. If I'm looking for a tool to unroll loops, I can use foreach with a tuple, or static foreach. Both should behave the same. Perhaps the deprecation path should include a removal of straight foreach over a tuple working (use static foreach explicitly). This would make the distinction even more obvious. -Steve
Jul 12 2017
On Wednesday, 12 July 2017 at 10:57:37 UTC, Steven Schveighoffer wrote:Perhaps the deprecation path should include a removal of straight foreach over a tuple working (use static foreach explicitly). This would make the distinction even more obvious.I'd also vote for gradual removal of foreach over a tuple. It would be one less awkward moment when teaching D.
Jul 12 2017
On Monday, 10 July 2017 at 08:53:42 UTC, Mike Parker wrote:As promised, since there has been zero feedback on DIP 1010, "Static foreach", in either the Draft or Preliminary review rounds, I'm going to skip the normal two-week feedback cycle on the Formal review. If there are no major criticisms or objections raised in this thread, then sometime on Thursday of this week I'll send Walter & Andrei an email kicking off the decision process.Thanks for all the feedback. I don't see anything that is a blocker from moving forward, so I'll cut it off here and move along.
Jul 13 2017