September 15, 2016
Why does it do that?
And seemingly it does not require it for opApply with more than two arguments.
September 16, 2016
On Thursday, 15 September 2016 at 18:23:14 UTC, Q. Schroll wrote:
> Why does it do that?
> And seemingly it does not require it for opApply with more than two arguments.

Here's what the comment says:

https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d#L929

// opApply with >2 parameters. count the delegate args.
    // only works if it is not templated (otherwise we cannot count the args)
    void each(Iterable)(Iterable r)
        if (!isRangeIterable!Iterable && !isForeachIterable!Iterable &&
            __traits(compiles, Parameters!(Parameters!(r.opApply))))
    {
        auto dg(Parameters!(Parameters!(r.opApply)) params) {
            pred(params);
            return 0; // tells opApply to continue iteration
        }
        r.opApply(&dg);
}

Usually, if you change elements while iterating, you need to `ref` them. If you leave out `ref` the following loop will finish after 'd'. If you put in `ref` you have an infinite loop.

void main()
{
  import std.stdio : writefln;
  auto arr = ['a', 'b', 'c', 'd'];
  foreach (ref i, c; arr)
  {
    if (c == 'c')
    {
      --i;
      writefln("index = %d", i);
    }
  }
}