Thread overview
Deprecate assigning a slice to a static array?
Aug 31, 2022
Nick Treleaven
Aug 31, 2022
Nick Treleaven
Aug 31, 2022
Salih Dincer
Aug 31, 2022
Salih Dincer
Aug 31, 2022
bauss
Aug 31, 2022
Nick Treleaven
August 31, 2022

I didn't know initializing a static array from a slice of unknown length was allowed until I saw:
https://dlang.org/blog/2022/06/21/dip1000-memory-safety-in-a-modern-system-programming-language-pt-1/

// allocated in static program memory
auto hello1 = "Hello world!";
// allocated on the stack, copied from hello1
immutable(char)[12] hello2 = hello1;

How does the compiler know hello1.length at compile-time for the initialisation of the static array? It doesn't - there is a runtime check. I think it's better to require slicing of either the static array or the slice to make that clear:

int[] s = ...;
int[2] a;
a[] = s; // copy slice to slice, checking lengths match
a = s[0..2]; // copy 2 elements, no runtime check

(The last line is recognised as a slice of compile-time known length - described here:
https://dlang.org/spec/expression.html#slice_to_static_array).

For just a = s;, the programmer may have accidentally assumed s was a static array, or forgot to slice it to match the static array size. I think it's bug prone. It's also hard to detect if the slice normally has a matching length but in some weird runtime condition it doesn't and it throws. It's also a hidden runtime check that could hurt performance.

Note this doesn't seem to be documented in the spec yet:
[1] https://dlang.org/spec/arrays.html#assignment
[2] https://dlang.org/spec/arrays.html#array-copying
[3] https://dlang.org/spec/arrays.html#array-initialization

[1] actually has:

//s = a; // error, as a's length is not known at compile-time

I added that to the docs but it's wrong (if this feature is to stay I will make a PR to fix that line).

[2] only talks about slices. [3] doesn't mention initializing from an lvalue. AssignExpression just links to Array Copying [2] and Array Setting (for assigning a single element).

Would deprecating this break much code? Perhaps an exploratory dmd PR could be made to see if it breaks any of the tested key projects?

August 31, 2022

On Wednesday, 31 August 2022 at 12:04:10 UTC, Nick Treleaven wrote:

>
a = s[0..2]; // copy 2 elements, no runtime check

Here of course there is a runtime check that s.length >= 2. But it is clearer the check is happening and the user could avoid that check with .ptr.

August 31, 2022

On Wednesday, 31 August 2022 at 12:04:10 UTC, Nick Treleaven wrote:

>

I didn't know initializing a static array from a slice of unknown length was allowed until I saw:
https://dlang.org/blog/2022/06/21/dip1000-memory-safety-in-a-modern-system-programming-language-pt-1/

The reverse is also possible and note that .capacity is 0 in any case.

// D 2.0.83

import std.stdio;
void main()
{
  int[4] abcd = [0, 1, 2, 3];
  int[] slice = abcd[];
  slice.writeln(": ", slice.capacity);

  int[] dcba = [ 7, 6, 5, 4, 3, 2, 1, 0];
  int[4] arr = dcba[4..$];
  arr.writeln(": ", arr.capacity);

  arr = dcba[0..4];
  arr.writeln(": ", arr.capacity);
}/*

  [0, 1, 2, 3]: 0
  [3, 2, 1, 0]: 0
  [7, 6, 5, 4]: 0

Process finished.
*/

SDB@79

August 31, 2022

On Wednesday, 31 August 2022 at 15:36:54 UTC, Salih Dincer wrote:

>

The reverse is also possible and note that .capacity is 0 in any case.

So is slice really a slice?

SDB@79

August 31, 2022

On Wednesday, 31 August 2022 at 15:41:14 UTC, Salih Dincer wrote:

>

On Wednesday, 31 August 2022 at 15:36:54 UTC, Salih Dincer wrote:

>

The reverse is also possible and note that .capacity is 0 in any case.

So is slice really a slice?

SDB@79

Yes, because a slice isn't a type but a concept.

August 31, 2022

On Wednesday, 31 August 2022 at 15:36:54 UTC, Salih Dincer wrote:

>

int[] dcba = [ 7, 6, 5, 4, 3, 2, 1, 0];
int[4] arr = dcba[4..$];

The above conversion would also be deprecated because dcba[4..$] is not one of the slice expression forms with compile-time known length (the compiler doesn't know what $ is). dcba[4..8] could be used instead.

In case the runtime matching length check is desired with static array initialization (i.e. check dcba.length is not > 8), it would be written as:

int[4] arr; // optimizer can remove `= 0`
arr[] = dcba[4..$]; // matching length check now more obvious
>

arr = dcba[0..4];

That is fine as I mentioned, it's one of the forms recognised.