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