bug in foreach continue

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Mar 17 06:10:23 PDT 2017


On Friday, March 17, 2017 11:53:41 Michael via Digitalmars-d-learn wrote:
> On Friday, 17 March 2017 at 11:30:48 UTC, Jonathan M Davis wrote:
> > On Friday, March 17, 2017 01:55:19 Hussien via
> > Digitalmars-d-learn wrote:
> >
> > I tend to agree with this. If the foreach is static, and
> > continue and break are just going to be ignored, then they
> > should just be illegal. Allowing them is just going to confuse
> > people. Now, making it so that they actually work statically
> > has some interesting possibilities, but that would fall apart
> > as soon as you have any constructs that would use continue or
> > break (e.g. a loop or switch statement) inside the static
> > foreach, and it might break code in rare cases. So, we're
> > probably better off just making them illegal. But having them
> > be legal just seems disingenious, since they don't do anything.
> >
> > - Jonathan M Davis
>
> What exactly IS happening in the case of a continue in a
> static-if? I could sort of imagine that maybe if you were
> expecting the loop to be unrolled, that you then have a continue
> statement in the correct part of the unrolled loop. But I take it
> this isn't what's happening?

Okay. I completely misunderstood what was happening based on the previous
posts. For instance, from this test

import std.meta;
import std.stdio;

void main()
{
    foreach(str; ["hello", "world", "foo", "bar"])
    {
        foreach(i; AliasSeq!(0, 1, 2, 3, 4))
        {
            static if(i / 2 == 0)
                writefln("%s: %s", i, str);
            else
            {
                writefln("%s: skipping %s", i, str);
                break;
            }
        }
        writeln();
    }
}

it looks like break and continue _are_ used at compile time, since it
prints

0: hello
1: hello
2: skipping hello

0: world
1: world
2: skipping world

0: foo
1: foo
2: skipping foo

0: bar
1: bar
2: skipping bar

whereas if the break were just compiled in to be run at runtime, you never
would have seen any of the strings past "hello" in the outer loop get
printed. So, the issue is _not_ that continue and break are always treated
as runtime constructs or outright ignored. And if we have

import std.meta;
import std.stdio;

void main()
{
    foreach(str; AliasSeq!("a", "b", "c"))
    {
        static if(str == "a")
            continue;
        writeln(str);
    }
}

it prints

b
c

because when the loop is unrolled, wirteln isn't compiled in (and in fact,
if you compile with -w, the code won't compile at all, because writeln is
unreachable in the "a" iteration).

On the other hand, if we have

import std.meta;
import std.stdio;

void main()
{
    foreach(str; AliasSeq!("a", "b", "c"))
    {
        static if(str == "a")
            continue;
        pragma(msg, str);
    }
}

then we get

a
b
c

which is what the OP was complaining about. Now, as to whether that's a bug
or not, I don't know. pragma(msg, ...) prints whenever it's compiled, and as
shown by the compilation error when you compile in the -w case, the code
after the static if _is_ compiled in. It just ends up not being run.
Certainly, the continue and break are _not_ skipped like I originally
understood to be the case. So, that's not the bug. If there _is_ a bug, it's
that the rest of the code in the loop after the static if is compiled after
the continue, and I don't know that that is a bug. Remember that this is
basically doing loop unrolling, which is not necessarily the same thing as
you would expect from a "static foreach." It's not like we're building a
string mixin here. It's more like the same code is being copy-pasted over
and over but potentially with some tweaks on a given iteration.

So, I'm not at all convinced that this is a bug, but I do agree that the
semantics are a bit wonky. Regardless, based on what happens with the
writeln case, it's clearly the case that you should be using an else branch
if you want to cleanly use a continue in a foreach like this.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list