Memory without Destination
So one sunny day you do casual D coding and make use of array slicing to perform an element-wise operation.
void main() {
int[] a = [1, 1, -1, 0, 1, 0];
a[] += 1; // [2, 2, 0, 1, 2, 1]
}
Nicely works! Now, I’d like to sum it with another array.
void main() {
int[] a = [1, 1, -1, 0, 1, 0];
a[] += 1; // [2, 2, 0, 1, 2, 1]
int[] b = [10, 20, 30, 40, 50, 60];
a[] += b[]; // [12, 22, 30, 41, 52, 61]
}
Smooth! And in case I want to reset the array to zeros, I can just do a[] = 0;
.
Finally, let me store the sum of the a
and b
arrays in some new variable c
.
void main() {
int[] a = [1, 1, -1, 0, 1, 0];
a[] += 1; // [2, 2, 0, 1, 2, 1]
int[] b = [10, 20, 30, 40, 50, 60];
a[] += b[]; // [12, 22, 30, 41, 52, 61]
int[] c = a[] + b[];
}
Next thing you see when you try to compile the code above:
Error: array operation `a[] + b[]` without destination memory not allowed
Huh? This is strange because I totally expected this to work. What’s going on here?
I know, it does look confusing, especially when int c = 1 + 2;
is correct.
Here D chooses performance over convenience.
In order for int[] c = a[] + b[]
to work, the runtime needs to evaluate a[] + b[]
and copy its result to c
.
The operation is costly unlike int c = 1 + 2;
.
Many languages will allocate in such a cases, D puts performance first.
That’s why D tries to delay array evaluation for as long as possible and int[] c
is not getting initialized.
You need to do it explicitly.
void main() {
int[] a = [1, 1, -1, 0, 1, 0];
a[] += 1; // [2, 2, 0, 1, 2, 1]
int[] b = [10, 20, 30, 40, 50, 60];
a[] += b[]; // [12, 22, 30, 41, 52, 61]
int[6] c;
c[] = a[] + b[]; // [22, 42, 60, 81, 102, 121]
}
If you need to keep c
size flexible, you can control its size via its length
property.
int[] c;
c.length = 2;
c[] = a[] + b[]; // [22, 42]
Another way of getting around this is to use zip
and map
to create a lazy expression.
void main() {
int[] a = [1, 1, -1, 0, 1, 0];
a[] += 1; // [2, 2, 0, 1, 2, 1]
int[] b = [10, 20, 30, 40, 50, 60];
a[] += b[]; // [12, 22, 30, 41, 52, 61]
auto c = zip(a, b).map!(t => t[0] + t[1]); // evaluated when required
}
That’s it! You have just learnt about one of the D gotchas: you must provide a destination in order to allocate arrays in-place.