Thread overview
Is there any reason to use non-ref foreach?
Aug 31, 2018
Dukc
Aug 31, 2018
bauss
Aug 31, 2018
James Blachly
Aug 31, 2018
Dukc
Sep 03, 2018
Andrea Fontana
Sep 04, 2018
Dukc
Sep 04, 2018
Andrea Fontana
Sep 04, 2018
Dukc
August 31, 2018
For me, it seems that for generality you should always add ref into foreach loop variable. The reason is this:

import std.experimental.all;

struct NoCopies
{   @disable this(this);
    int payload;
}

void main()
{   auto range = new NoCopies[20];
    foreach(const ref el; range) el.payload.writeln;
}

Without ref qualifier in el, this won't work because it would make a copy. Unlike ref as a function argument, it does not enforce refness:

import std.experimental.all;

void main()
{   auto range = iota(20).map!(x => x + 2);
    foreach(const ref el; range) el.writeln;
}

This compiles, even though range elements are rvalues.

This seems to imply, for me, that for generality one should always use ref in foreach loop variables. If the vairable has to be guarded against changes, it should const ref, not unqualified.

But considering unqualified is the default, I am probably missing something here. Performance?
August 31, 2018
On Friday, 31 August 2018 at 09:59:20 UTC, Dukc wrote:
> For me, it seems that for generality you should always add ref into foreach loop variable. The reason is this:
>
> import std.experimental.all;
>
> struct NoCopies
> {   @disable this(this);
>     int payload;
> }
>
> void main()
> {   auto range = new NoCopies[20];
>     foreach(const ref el; range) el.payload.writeln;
> }
>
> Without ref qualifier in el, this won't work because it would make a copy. Unlike ref as a function argument, it does not enforce refness:
>
> import std.experimental.all;
>
> void main()
> {   auto range = iota(20).map!(x => x + 2);
>     foreach(const ref el; range) el.writeln;
> }
>
> This compiles, even though range elements are rvalues.
>
> This seems to imply, for me, that for generality one should always use ref in foreach loop variables. If the vairable has to be guarded against changes, it should const ref, not unqualified.
>
> But considering unqualified is the default, I am probably missing something here. Performance?

It makes sense in your simplified examples, but in practice it doesn't, because it will depend on each situation, what type of data you're enumerating etc.

And I bet you there are some gotchas using just ref.

In reality you're micro-optimizing something that doesn't require it.

Remember that basically the difference is this.

foreach (i; values) {
 ...
}

for (int _ = 0; _ < values; _++)
{
    auto i = values[_];

    ...
}

VS

foreach (ref i; values) {
 ...
}

for (int _ = 0; _ < values; _++)
{
    auto i = &values[_];

    ...
}

So basically ... Instead of copying the value, you're just copying the address.

I can't see the benefit other than added complexity.
August 31, 2018
On Friday, 31 August 2018 at 12:52:17 UTC, bauss wrote:
>
> So basically ... Instead of copying the value, you're just copying the address.
>
> I can't see the benefit other than added complexity.

I assume a benefit could be observed if you are copying a large struct instead of an int.
August 31, 2018
On Friday, 31 August 2018 at 12:52:17 UTC, bauss wrote:
> In reality you're micro-optimizing something that doesn't require it.

I think you misunderstood. I wasn't trying to optimize, I was looking for a general way to iterate.

> I can't see the benefit other than added complexity.

I just explained it. Iterating by ref works with elements that have postblits disabled, iterating by value doesn't.

I was wondering that if iterating by ref is the most general way to iterate, why it isn't the default? Is there some big implication in using it?
September 03, 2018
On Friday, 31 August 2018 at 09:59:20 UTC, Dukc wrote:
> For me, it seems that for generality you should always add ref into foreach loop variable. The reason is this:

One good reason:
https://forum.dlang.org/thread/dlhrrgvzmhladnphidei@forum.dlang.org


September 04, 2018
On Monday, 3 September 2018 at 13:34:36 UTC, Andrea Fontana wrote:
> On Friday, 31 August 2018 at 09:59:20 UTC, Dukc wrote:
>> For me, it seems that for generality you should always add ref into foreach loop variable. The reason is this:
>
> One good reason:
> https://forum.dlang.org/thread/dlhrrgvzmhladnphidei@forum.dlang.org

I am almost sure it will stay how it is, because of the sheer amount of breakage changing that would cause. I still agree that in princliple, the general way to iterate should be something else (auto ref?). But as with autodecoding, the present way is already in too wide use to be worth changing.

But I think we need an official line to confirm whether one can use that without risking a deprectation.
September 04, 2018
On Tuesday, 4 September 2018 at 07:06:43 UTC, Dukc wrote:
> On Monday, 3 September 2018 at 13:34:36 UTC, Andrea Fontana wrote:
>> On Friday, 31 August 2018 at 09:59:20 UTC, Dukc wrote:
>>> For me, it seems that for generality you should always add ref into foreach loop variable. The reason is this:
>>
>> One good reason:
>> https://forum.dlang.org/thread/dlhrrgvzmhladnphidei@forum.dlang.org
>
> I am almost sure it will stay how it is, because of the sheer amount of breakage changing that would cause. I still agree that in princliple, the general way to iterate should be something else (auto ref?). But as with autodecoding, the present way is already in too wide use to be worth changing.
>
> But I think we need an official line to confirm whether one can use that without risking a deprectation.

Waiting for this to be merged:
https://github.com/dlang/dmd/pull/8437

September 04, 2018
On Tuesday, 4 September 2018 at 08:17:14 UTC, Andrea Fontana wrote:
>
> Waiting for this to be merged:
> https://github.com/dlang/dmd/pull/8437

Well, it seems Andrei has already approved the concept. well, THAT is a good reason to avoid this paradigm. Thanks for the info.