DIP 1025--Dynamic Arrays Only Shrink, Never Grow--Community Review Round 1

John Colvin john.loughran.colvin at gmail.com
Tue Nov 12 15:54:22 UTC 2019


On Monday, 11 November 2019 at 10:27:26 UTC, Mike Parker wrote:
> This is the feedback thread for the first round of Community 
> Review for DIP 1025, "Dynamic Arrays Only Shrink, Never Grow":
>
> https://github.com/dlang/DIPs/blob/1b525ec4c914c06bc286c1a6dc93bf1533ee56e4/DIPs/DIP1025.md

See here for my response: 
https://gist.github.com/John-Colvin/c9c0b79bc9d47ed8d57ec9e959d0542b


Included below for convenience and record:


The DIP provides 2 examples to justify itself:

1) unpredictable mutable aliasing after appends

2) unpredictable changes of ownership caused by appends

They can share the same cause (`~=`), but are two distinct 
symptoms, and can also have other causes. They have a unifying 
aspect which is unpredictable aliasing.

The breakage of the DIP is immense, so there needs to be a 
commensurately large upside and no reasonable alternative path 
with less breakage.


### Let's consider the first example:

```D
int[] slice = cast(int*)malloc(10 * int.sizeof)[0 .. 10];
slice ~= 1;
free(slice.ptr); // Oops!
```

`free` is not an `@safe` operation and requires some conditions 
to be met for correct use. These conditions are as follows:
  - `free` happens after all accesses to the allocation referenced 
by the passed pointer.
  - the allocation referenced by the passed pointer was made by 
`{m,c,re}alloc`

as such, you can't really ever call `free` without completely 
trusting the path by which the data travelled, from inception 
(`{m,c,re}alloc`) to the call to `free`. This may be achieved by 
a variety of ways (e.g. a `MallocSlice` type that encapsulates 
the slice, or by having the path be very short and doing it 
manually) but fundamentally if I write a function taking a slice 
and then freeing the pointer, I cannot mark it as `@trusted`, 
regardless of whether `~=` is allowed or not.

That `~=` will cause a new array to be allocated unpredictably is 
not the problem, the problem is that it can happen at all. If we 
look at it probabilistically: the problem is not that the 
probability of re-allocation is in `(0, 1)`, the problem is that 
it's not `0`. *Someone can write `slice = slice ~ 1` and get the 
same behaviour, so my considerations when calling `free` have not 
changed by disallowing `~=`.*

### On to the second example:

```D
enum { dead, alive }
int[] cat = new int[6];
cat[5] = alive;
int[] b = cat;
b ~= 1;      // may or may not move b to new location
b[5] = dead; // indeterminate whether cat[5] is dead or alive
```

This is a sticky one. `~=` applied to data where there are >1 
references and >0 are mutable is liable to cause problems of 
unpredictable action at a distance. Removing `~=` makes it 
slightly harder to do this, but seeing as it's so very easy to do 
the same thing in other ways (`a = b ? a : (a ~ 2)` and many 
other trivial examples) it arguably doesn't matter much. I could 
believe it makes it less likely to do by accident.

## Conclusion:

Overall, this change seems to not buy anyone much, but costs a 
lot. It correctly identifies a problem (or 2 problems, depending 
how you  look at it), but the proposed solution does not appear 
on a simple reading to solve the problem.

The DIP does not provide any examples of what is directly enabled 
by the change and I was not able to infer it from the current 
text.

*The author should explain what previously impossible/unsafe code 
can now be made possible/safe given the proposed change.*


More information about the Digitalmars-d mailing list