In my D code I have inserted few times the same bug, that I show
here with a simplified example.
I have to create a matrix like this:
0 10 20 30
0 11 21 31
0 12 22 32
There are many ways to inizialize a matrix like that, this is one
way, but it's not complete:
import std.stdio;
void main() {
auto M = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
foreach (r, row; M)
foreach (c, ref item; row)
item = c * 10 + r;
writefln("%(%s\n%)", M);
}
It outputs:
[0, 10, 20, 30]
[1, 11, 21, 31]
[2, 12, 22, 32]
To complete the algorithm, that is to not touch the first column,
I can use just a slice in the second foreach, to not touch the
first column:
import std.stdio;
void main() {
auto M = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
foreach (r, row; M)
foreach (c, ref item; row[1 .. $])
item = c * 10 + r;
writefln("%(%s\n%)", M);
}
But this introduces the bug:
[0, 0, 10, 20]
[0, 1, 11, 21]
[0, 2, 12, 22]
Slicing 'row' from the second item I avoid to write on the first
cells of each row, but the 'c' index doesn't get sliced, it
starts from zero still. One correct version needs to increment c
by one in the formula:
import std.stdio;
void main() {
auto M = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
foreach (r, row; M)
foreach (c, ref item; row[1 .. $])
item = (c + 1) * 10 + r;
writefln("%(%s\n%)", M);
}
Another solution is to ignore the c==0:
foreach (r, row; M)
foreach (c, ref item; row)
if (c != 0)
item = c * 10 + r;
I don't consider this a D/Phobos bug, but maybe there are library
ways to help me (and others) avoid it.
In this enhancement request I have asked for an enumerate() in
Phobos:
http://d.puremagic.com/issues/show_bug.cgi?id=5550
enumerate() is similar to the Python built-in iterable, it just
yields pairs of (count,item), counting the items of a given
iterable (range).
If enumerate() is well implemented it's one way to avoid that
problem (other solutions are possible), now 'c' gets sliced, so
it doesn't start from zero:
import std.stdio;
void main() {
auto M = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
foreach (r, row; M)
foreach (c, ref item; enumerate(row)[1 .. $])
item = c * 10 + r;
writefln("%(%s\n%)", M);
}
Bye,
bearophile