I think the online documentation (http://dlang.org/statement.html#ForeachStatement) is not sufficient.
foreach (e; aggr) { ...body...} Current dmd translates above foreach statement like follows. 1. If aggr has opApply or opApplyReverse, it's used. 2. If aggr has empty/front/popFront: 2a. If aggr has slice operation, it's translated to: for (auto __r = aggr[]; // If aggr is a container (e.g. std.container.Array), // foreach will get its range object for the iteration. !__r.empty; __r.popFront()) { auto e = __r.front; ...body... } 2b. If aggr doesn't have slice operation, it's translated to: for (auto __r = aggr; // If aggr is copyable, saves the original range. !__r.empty; __r.popFront()) { auto e = __r.front; ...body... } 3. If aggr is static or dynamic array, it's translated to: for (auto __tmp = aggr[], __key = 0; // If aggr is static array, get its slice for iteration. !__key < __tmp.length; ++__key) { auto e = __tmp[__key]; ...body... } These come from the dmd source code. https://github.com/D-Programming-Language/dmd/blob/master/src/opover.c#L1226 https://github.com/D-Programming-Language/dmd/blob/master/src/statement.c#L1522 Bye Kenji Hara 2012/7/11 monarch_dodra <monarch_do...@gmail.com>: > If you create a class/struct that can give you a (forward) range via > "opSlice()", and that range gives you access to "opApply", then you get two > different behaviors: > > ---- > MyClass arr = ...; > > foreach(a; arr) > ... > > foreach(a; arr[]) > ... > > ---- > In the first case, foreach will call opSlice(), and then walk through the > resulting arr[] range with the front/popFront/empty troika. > > In the second case, foreach will call opApply on the range "arr[]". > > ---- > I'm wondering if this is the correct behavior? In particular, since foreach > guarantees a call to opSlice(), so writing "arr[]" *should* be redundant, > yet the final behavior is different. > > That said, the "issue" *could* be fixed if the base class defines opApply > as: "return opSlice().opApply(dg)" (or more complex). However: > a) The implementer of class has no obligation to do this, since he has > provided a perfectly valid range. > b) This would force implementers into more generic useless boilerplate code. > > What are your thoughts? Which is the "correct" solution? Is it a bug with > foreach, or should the base struct/class provide an opApply? > > PS: Related: "foreach over range (with opApply) should save range." > http://d.puremagic.com/issues/show_bug.cgi?id=4347 > On this assigned issue, is the conclusion that foreach will eventually save > the range?