There are two problems: 1. std.container.Array.(front, back, opIndex, ...) doesn't return its elements by ref. 2. std.algorithm.map doesn't consider original range's ref-ness.
Bye. Kenji Hara 2012/7/2 monarch_dodra <monarch_do...@gmail.com>: > I think this is a pretty serious bug: when one writes: "foreach(ref a, > range)", the underlying (ref'd) object will ONLY get modified if the range > object provides a "ref T front()" method. > > What is worrisome is that: > a) The code compiles anyways. > b) This even happens when range provides a "void front(T t)" method. > > Here is the bug in action, with the very standard Array class, as well as > the generic Map algorithm: > ---- > import std.container; > import std.stdio; > import std.algorithm; > > void main() > { > Array!int arr; > arr.length = 3; > > foreach(a; arr) > a = 2; > > map!("a+=2")(arr[]); > > writeln(arr[]); > } > ---- > Output: > ---- > [0, 0, 0] > ---- > > As you can see, not only is "foreach" broken, but so is any algorithm that > tries to mutate an Array. > > Note that "Array" itself can be fixed by my recommendation here: > http://forum.dlang.org/thread/bkozswmsgeibarowf...@forum.dlang.org > > However, in the case of containers that can't return a ref'ed front (eg > Array!bool), this is actually a double bug: > > 1) foreach: It makes compile time call to "T front()" regardless of context. > Because of this, even when we write "a = 2", a straight up assignment to a > temporary takes place, rather than compiling as "arr.front(2)". > > 2) front: Unlike opIndex, front is not an operator. This means that writing > code such as "arr.front += 5" or "++arr.front" is not supported by the > language (when front returns by value). This means the implementer of a > Range (which can't return a ref'd front) has absolutely no way of > intercepting operations that want to occur directly on front