On Monday, 5 July 2021 at 13:10:55 UTC, Rekel wrote:
> Am I the only one slightly unamused by how arrays/ranges work? They keep backfiring on me, or require weird additions other languages wouldn't require such as manually changing .length, or worrying about what operation returns a copy etc. (Kind of jealous of java's ease here)
It's easy to start to learn about D's dynamic arrays and ranges and then welcome them as false friends. They're genuinely great, but they're not quite the same thing as what you recognized them as, and as long as this confusion persists, frustration will occur. You were probably expecting dynamic arrays to work like a class:
import std.array, std.algorithm;
class Array {
int[] data;
this(int[] xs) { data = xs; }
}
void removeEvens(Array a) {
a.data = a.data.filter!"a%2".array;
}
unittest {
auto h = new Array([1, 2, 4, 5]);
h.removeEvens;
assert(h.data == [1, 5]);
}
removeEvens gets a reference to a thing, it mutates it, job done.
An int[] parameter though is a copy of a slice. It's more like like this struct:
import std.array, std.algorithm;
struct Array {
int* data;
size_t length;
this(int[] xs) { data = xs.ptr; length = xs.length; }
}
void removeEvens(Array a) {
for (size_t i = 0; i < a.length; ++i) {
if (a.data[i] % 2 == 0) {
a.data[0 .. a.length].remove!(SwapStrategy.stable)(i);
a.length--;
i--; // !
}
}
}
unittest {
auto h = Array([1, 2, 4, 5]);
h.removeEvens;
assert(h.data[0 .. h.length] == [1, 5, 5, 5]);
}
before removeEvens exits, its copy of a has become the intended 2-length array with only odd elements, but that copy is thrown away and the original 4-length array just sees its memory changed to have a 2-array prefix of its old odd elements, and then it has a suffix of garbage.
Of ranges, they look like visual pipelines of functions that directly alter data that flows through them, but their actual result is the pipeline and not the data. Range functions take shorter bits of pipeline as an argument and produce longer bits of pipeline as a result, and their errors are all pipeline related: "I only connect to sorted ranges", "I only connect to randomly-accessible ranges", etc.
On Monday, 5 July 2021 at 13:34:50 UTC, Rekel wrote:
> Also, is my use of long correct? The documentation wasn't very clear on the return type of remove, just calling it a 'number'.
What use of long?
remove returns the same type of range as it gets:
Range remove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range, Offset offset)
^^^^^ ^^^^^ ^^^^^
The first Range is the return type, the second Range is a template type parameter, and the third Range is the argument type. When you remove from an int[] you're calling a specialized function that returns an int[]