Is old style compile-time foreach redundant?
Steven Schveighoffer
schveiguy at yahoo.com
Tue Jan 9 19:24:11 UTC 2018
On 1/9/18 11:35 AM, H. S. Teoh wrote:
> On Tue, Jan 09, 2018 at 10:57:03AM -0500, Steven Schveighoffer via Digitalmars-d-learn wrote:
>> I may have been misleading when I made my first comment. What I mean
>> is that you *can't* break or continue a static foreach, even with
>> labels. However, you *can* do it to a standard foreach over a tuple.
>> This may be one reason you want to use a tuple-foreach over a static
>> foreach.
> [...]
>
> Actually, that's wrong too. Tuple-foreach does not interpret
> break/continue either. Here's a proof:
>
> alias Seq(A...) = A;
> foreach (i; Seq!(0, 1, 2, 3)) {
> static if (i==2)
> break;
> static assert(i < 3); // will fail on the 4th iteration
> }
>
> What actually happens is that all iterations are unrolled, then the
> unreachable iterations are elided by the optimizer during codegen. The
> foreach itself is not affected by break/continue at all.
A break or continue is simply a goto underneath. A goto in an unrolled
loop isn't much different than a goto in a um... rolled loop :) It's
just that there are copies of each loop body, and the gotos need copies
of the labels.
So no, it's not "interpreted" by the foreach statement, but the foreach
statement provides the anchors for the goto label targets.
e.g.:
int x;
foreach(i; Seq!(0, 1, 2, 3)) {
x += i;
static if(i % 2) continue;
x *= i;
}
=>
int x;
{
x += 0;
x *= 0;
}
{
x += 1;
goto label1;
x *= 1;
}
{
label1:
x += 2;
x *= 2;
}
{
x += 3;
goto label2;
x *= 3;
}
label2:
And then of course, the optimizer weeds out the unreachable statements.
Doing this with static foreach wouldn't be as pleasant. You'd have to
branch the entire loop body, or use a goto in the case of a break.
-Steve
More information about the Digitalmars-d-learn
mailing list