Thread overview
[Issue 11934] Allow `ref` in `foreach` over range iff `front` returns by `ref`
Aug 08, 2016
Ketmar Dark
Dec 19, 2017
Nick Treleaven
Jun 14, 2018
Richard Cattermole
Jun 14, 2018
Richard Cattermole
Feb 21, 2019
Simen Kjaeraas
Feb 25, 2019
Dlang Bot
Mar 01, 2019
Dlang Bot
August 08, 2016
https://issues.dlang.org/show_bug.cgi?id=11934

Ketmar Dark <ketmar@ketmar.no-ip.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ketmar@ketmar.no-ip.org

--
December 19, 2017
https://issues.dlang.org/show_bug.cgi?id=11934

Nick Treleaven <nick@geany.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |nick@geany.org
           See Also|                            |https://issues.dlang.org/sh
                   |                            |ow_bug.cgi?id=11935

--
June 14, 2018
https://issues.dlang.org/show_bug.cgi?id=11934

Richard Cattermole <alphaglosined@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schuetzm@gmx.net

--- Comment #1 from Richard Cattermole <alphaglosined@gmail.com> ---
*** Issue 15351 has been marked as a duplicate of this issue. ***

--
June 14, 2018
https://issues.dlang.org/show_bug.cgi?id=11934

Richard Cattermole <alphaglosined@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |alphaglosined@gmail.com

--- Comment #2 from Richard Cattermole <alphaglosined@gmail.com> ---
A more substantial example of why this is a problem:

---
import std.stdio;
import std.algorithm;

struct A {
    this(int i) { id=counter++; counterLive[id] = 1; writeln("CTOR ", id); }
    ~this() { counterLive[id]--; writeln("DTOR ", id); }
    this(this) { counterLive[id]++;writeln("POSTBLIT ", id); }

    static size_t counter=1;
    static size_t[size_t] counterLive;
    size_t id;
}

void main() {
    foreach(ref r; [A(10), A(2), A(3)].map!(x => x)) { }

    foreach(k, v; A.counterLive)
        if (v > 0) writeln("A (", k, ") count ", v);
}
---

Output:

---
CTOR 1
CTOR 2
CTOR 3
POSTBLIT 1
POSTBLIT 1
DTOR 1
POSTBLIT 2
POSTBLIT 2
DTOR 2
POSTBLIT 3
POSTBLIT 3
DTOR 3
A (2) count 2
A (3) count 2
A (1) count 2
DTOR 3
DTOR 2
DTOR 1
---

The destructors for 3 copies never get called.

--
February 21, 2019
https://issues.dlang.org/show_bug.cgi?id=11934

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

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

--- Comment #3 from Simen Kjaeraas <simen.kjaras@gmail.com> ---
Simplified example:

import std.stdio;
import std.algorithm;

struct A {
    this(int i) { writeln("ctor ", &this); }
    ~this() { writeln("dtor ", &this); }
    this(this) { writeln("postblit ", &this); }
}

unittest {
    writeln("Without ref:");
    foreach(r; [1].map!(x => A(x))) { }
    writeln("With ref:");
    foreach(ref r; [1].map!(x => A(x))) { }
}

As we can see from the output, the dtor is correctly called in the non-ref case, but not in the ref case. Memory addresses are the same in both cases, and are stack addresses, so it's not a case of 'allocate on heap and let GC sort it out'.

As Denis points out though, it may be better for this not to compile than to compile and silently do something other than expected (even though the ref'ed struct is mutated, this is not reflected anywhere since it's a temporary).

--
February 25, 2019
https://issues.dlang.org/show_bug.cgi?id=11934

Dlang Bot <dlang-bot@dlang.rocks> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |pull

--- Comment #4 from Dlang Bot <dlang-bot@dlang.rocks> ---
@trikko updated dlang/dmd pull request #8437 "Fixed issue 11934. Range with a non-ref front + foreach(ref...)" fixing this issue:

- Fixed issue 11934. Range with a non-ref front + foreach(ref...)

https://github.com/dlang/dmd/pull/8437

--
March 01, 2019
https://issues.dlang.org/show_bug.cgi?id=11934

Dlang Bot <dlang-bot@dlang.rocks> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |FIXED

--- Comment #5 from Dlang Bot <dlang-bot@dlang.rocks> ---
dlang/dmd pull request #8437 "Fixed issue 11934. Range with a non-ref front + foreach(ref...)" was merged into master:

- 9a9bcb0cd78dda7ef0c6da0444e10af5b67cfa65 by Andrea Fontana:
  Fixed issue 11934. Range with a non-ref front + foreach(ref...)

https://github.com/dlang/dmd/pull/8437

--
August 19
https://issues.dlang.org/show_bug.cgi?id=11934

Nick Treleaven <nick@geany.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           See Also|                            |https://issues.dlang.org/sh
                   |                            |ow_bug.cgi?id=24679

--
August 19
https://issues.dlang.org/show_bug.cgi?id=11934

--- Comment #6 from Nick Treleaven <nick@geany.org> ---
(In reply to Denis Shelomovskii from comment #0)
>     static assert(!__traits(compiles, { foreach(ref n; S1()) { } })); // fails

This line still fails, so reopening. This could be fixed in the next edition.

--
August 19
https://issues.dlang.org/show_bug.cgi?id=11934

Nick Treleaven <nick@geany.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|FIXED                       |---

--