Thread overview
Quick question regarding dynamic array deletions
Sep 01, 2019
WhatMeWorry
Sep 01, 2019
Dennis
Sep 02, 2019
Jonathan M Davis
September 01, 2019
int[] a = [ 3, 7, 9 ];

1) a = [];
and
2) a = null;

sets both the .ptr property of the array to null, and the length to 0.

whereas

3) a.length = 0;

just sets the length to 0.


If all the above is correct, does this mean we should just stick to either of the first two forms and never use 3).  Maybe my question is when would be want to use 3) without also adjusting the .ptr ?


September 01, 2019
On Sunday, 1 September 2019 at 18:26:20 UTC, WhatMeWorry wrote:
> Maybe my question is when would be want to use 3) without also adjusting the .ptr ?

It matters when casting to a boolean, since an empty array with a non-null pointer is still `true` while an array with null pointer casts to `false`. This could be useful when you want to distinguish 'no array' and an empty array.

For example:
```
int[] getList(); // might fail

void main() {
  if (auto list = getList) {
    writeln(list); // could be an empty list
  } else {
    error("could not retrieve list"); // must be 'null' list
  }
}
```


September 01, 2019
On Sunday, September 1, 2019 12:42:54 PM MDT Dennis via Digitalmars-d-learn wrote:
> On Sunday, 1 September 2019 at 18:26:20 UTC, WhatMeWorry wrote:
> > Maybe my question is when would be want to use 3) without also adjusting the .ptr ?
>
> It matters when casting to a boolean, since an empty array with a non-null pointer is still `true` while an array with null pointer casts to `false`. This could be useful when you want to distinguish 'no array' and an empty array.
>
> For example:
> ```
> int[] getList(); // might fail
>
> void main() {
>    if (auto list = getList) {
>      writeln(list); // could be an empty list
>    } else {
>      error("could not retrieve list"); // must be 'null' list
>    }
> }
> ```

This is a difference, but it's also a rather error-prone approach. It's rarely the case that it's a good idea to differentiate null from empty with dynamic arrays, because too many operations don't treat them as different from one another. There are people who do it, and it can work if you're very careful, but it's very error-prone. That's also why using a dynamic array in a boolean condition like this is a code smell. If you're reading someone else's code that does this, unless there's a comment clarifying things, you generally can't assume that it's working as intended, because the odds are very high that the person who wrote the code misunderstood how dynamic arrays work in boolean conditions. And even if you wrote the code and do understand the difference, it's very easy to inadvertently end up with a null array when you were previously getting an empty one or to end up with an empty one where you were getting null.

Personally, about the only time that I would consider differentiating dynamic arrays based on null would be when the dynamic array would be null, because it would either have been returned as a null literal, or it would have been a dynamic array which was only default-initialized - and even then, I wouldn't do it if there were code in between the point of initialization and the check which did much with the array beyond initialize it, because the risk of getting null when you don't expect it is too high - especially if other people are working on the code as well. And there are plenty of people who would argue that Nullable should be used in such situations rather than ever trying to distinguish between null and empty.

Certainly, I would argue that under normal circumstances, assigning null to a dynamic array is what you should be doing rather than setting its length to 0, because then, that reference to the dynamic array has been removed, and that increases the chances of the GC being able to collect it. The primary exception would be when you intend to set the length to 0 in conjuction with using assumeSafeAppend so that you can reuse the memory, and for that to be safe to do, you have to know that either no other dynamic arrays referring to that block of memory exist or that they won't be used again without first being given a new value.

- Jonathan M Davis