foreach ref very broken: fails to call front(val)
kenji hara
k.hara.pg at gmail.com
Tue Jul 10 00:21:54 PDT 2012
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_dodra at 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/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