Remove array element within function

jfondren julian.fondren at gmail.com
Mon Jul 5 14:22:24 UTC 2021


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:

```d
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:

```d
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[]




More information about the Digitalmars-d-learn mailing list