Thread overview
[Issue 20901] arrays confuse static foreach
Jun 07, 2020
Simen Kjaeraas
Jun 09, 2020
Bolpat
Jun 10, 2020
Boris Carvajal
[Issue 20901] static foreach must deep-copy front() per iteration
Jun 10, 2020
Simen Kjaeraas
Dec 17, 2022
Iain Buclaw
June 07, 2020
https://issues.dlang.org/show_bug.cgi?id=20901

Simen Kjaeraas <simen.kjaras@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |simen.kjaras@gmail.com

--- Comment #1 from Simen Kjaeraas <simen.kjaras@gmail.com> ---
A shorter piece of code that demonstrates the issue:

import std.stdio : writeln;
struct S {
    int[] front = [0];
    bool empty() { return front[0] >= 2; }

    void popFront() {
        front[0]++;
    }
}

void main() {
    static foreach (e; S()) {
        writeln(e); // Writes [2] 2 times
    }
}


What happens is somewhat equivalent to this:

// Happens at compile-time:
S tmp;
auto value1 = tmp.front;
tmp.popFront();
auto value2 = tmp.front;
tmp.popFront();

// Happens at run-time:
writeln(value1);
writeln(value2);

Since there is no .dup anywhere to be found, value1 and value2 refer to the same array, so popFront() modifies both. Since all calls to popFront() happen at compile-time, before any of the values are used, only the final values are available. In fact, a deep duplication would be required for the values to be correct, which could cause other issues where you expect changing a value in one step would carry over to the next.


So, static foreach does not deal well with ranges that modify referenced data, and I'm not sure this is an issue that can be properly fixed. static foreach looks like 'please unroll this loop', but is... something else.

--
June 09, 2020
https://issues.dlang.org/show_bug.cgi?id=20901

--- Comment #2 from Bolpat <qs.il.paperinik@gmail.com> ---
I reduced that issue from a much larger code and was happy to push it under 50 lines of code.

Basically, what would have to happen is this:

// At compile-time:
S tmp;
enum value1 = tmp.front.deepcopy; // Note: enum
tmp.popFront();
enum value2 = tmp.front.deppcopy; // Note: enum
tmp.popFront();

// Happens at run-time:
writeln(value1);
writeln(value2);

I cannot imagine a situation where someone relying on a non-deep copy would not accept that this is not how static foreach works. Everything that is not a deep copy is plainly wrong.

--
June 10, 2020
https://issues.dlang.org/show_bug.cgi?id=20901

Boris Carvajal <boris2.9@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |boris2.9@gmail.com

--- Comment #3 from Boris Carvajal <boris2.9@gmail.com> ---
Also happens with pragma:

static foreach (e; S()) {
    pragma(msg, e);
}

--
June 10, 2020
https://issues.dlang.org/show_bug.cgi?id=20901

Simen Kjaeraas <simen.kjaras@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Hardware|x86                         |All
            Summary|arrays confuse static       |static foreach must
                   |foreach                     |deep-copy front() per
                   |                            |iteration
                 OS|Windows                     |All

--- Comment #4 from Simen Kjaeraas <simen.kjaras@gmail.com> ---
> Everything that is not a deep copy is plainly wrong.

It seems you're right. I though this code would cause problems, but it's statically disallowed:

static foreach (e; S()) {
    // Change an element that will also be present in the next iteration.
    e[0]++; // Error: cannot modify constant 2
    writeln(e);
}

If the above would compile, it'd be a clear issue. However, it doesn't, so it seems a deep copy should indeed work.

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=20901

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P2

--
December 13
https://issues.dlang.org/show_bug.cgi?id=20901

--- Comment #5 from dlangBugzillaToGithub <robert.schadek@posteo.de> ---
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/17961

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB

--