foreach ref very broken: fails to call front(val)
monarch_dodra
monarch_dodra at gmail.com
Mon Jul 2 05:44:58 PDT 2012
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/bkozswmsgeibarowfwvq@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
More information about the Digitalmars-d
mailing list