Skip to content

Latest commit

 

History

History
176 lines (130 loc) · 6.1 KB

DIP1039.md

File metadata and controls

176 lines (130 loc) · 6.1 KB

Static Arrays with Inferred Length

Field Value
DIP: 1039
Review Count: 0
Author: Lucien Perregaux
Implementation: None
Status: Community Review Round 1

Abstract

Allow $ in the brackets of array declarations in place of integer literals in order to infer array length.

Contents

Rationale

It is sometimes necessary to modify the contents of an existing static array initializer. For example,

int[2] array = [2, 4];

may at some point be changed to

int[3] array = [2, 4, 6];

The programmer must remember to update the integer literal in the static array declaration from 2 to 3, else face a compiler error.

The goal of this proposal is to eliminate the need to change the length specified in a static array declaration, with minimal impact on compile time, when modifying the length of the array's initializer.

Allowing the compiler to infer static array length will potentially save time and prevent compiler errors, as the programmer will no longer need to change the integer literal in the array declaration. This is especially beneficial when using betterC, where dynamic arrays are not available.

Conceptually, the new operator [$] documents that the programmer does not care about the array's length, but only that the array is a static array and not a slice.

No control-flow analysis is needed for this feature.

Prior Work

C and C++

In C and C++, we can declare a static array with inferred length like this:

int arr[] = {1, 2, 3};

In D, the identical syntax

int[] arr = [1, 2, 3];

is a slice, and not a static array.

See this C array initialization documentation.

D

Description

This feature is compatible with betterC and is only available for variable declarations with initializers. The $ in the array declaration's brackets will be replaced, at compile time, with the initializer's length.

Currently, a static array must be declared like this:

uint[2] arr = [ 2, 4 ];

When doing this, we have a DRY violation because we are spelling out the array's length even though the compiler knows the length of the array literal used to initialize it.

With the proposed feature, the above array could be declared like this:

uint[$] arr = [ 2, 4 ];    // $ = 2

There is no need to change the length of the static array every time we modify the length of its initializer. Eliminating that need is the only goal of this proposal.

More examples:

char[$] a1 = "cerise";              // OK, `$` is replaced with `6` at compile time

const int[] d = [1, 2, 3];
int[$] a2 = d;                      // OK, `$` = 3

auto a3 = cast(int[$]) [1, 2, 3];   // OK, `a3` is `int[3]` (same behavior as `cast(int[3])`)

int[$][] a4 = [[1, 2], [3, 4]];     // OK, same as `int[2][]`
foreach (int[$] a; a4) {}           // OK, we can deduce `$` because the length of `a4[0]` is equal to 2.

void foo(int[$] a5 = [1,2]);        // OK, `a5` has a default value, so we can deduce it's length

int[5] bar();
int[$] a6 = bar();                  // OK, `bar` returns a static array.

Those examples won't work:

int[$] b1;                          // Error: we don't know the length of `b1` at compile-time.

int[$][] = [[1, 2],[1, 2, 3]];      // Error: cannot implicitly convert expression `[[1, 2], [1, 2, 3]]` of
                                    // type `int[][]` to `int[2][]`

/*
 * `$` is equal to `3`, because it's the length of `b2[0]`.
 * As `b2[1]`'s length is 4, a RangeViolation error is thrown.
 */
int[][] b2 = [[1, 2, 3], [1, 2, 3]];
foreach (int[$] b; b2) {}           // Error: we don't know the length of `b` at compile-time.

void foo(int[$] b3);                // Error: we don't know the length of `b3` at compile-time.

int[$] bar(int[2] arr)              // Error: not allowed in functions declarations
{
    return arr ~ [3, 4];
}

int baz(int[$] b5)(string s);       // Error: not allowed in templates declarations

int[] d = [1, 2];
int[$] b6 = d;                      // Error, we don't know the length of `d` at compile-time.

Grammar changes

declaration spec

TypeSuffix:
        *
        [ ]
+       [ $ ]
        [ AssignExpression ]
        [ AssignExpression .. AssignExpression ]
        [ Type ]
        delegate Parameters MemberFunctionAttributes
        delegate Parameters
        function Parameters FunctionAttributes
        function Parameters


2. Arrays read right to left as well:
 int[3] x;     // x is an array of 3 ints
 int[3][5] x;  // x is an array of 5 arrays of 3 ints
 int[3]*[5] x; // x is an array of 5 pointers to arrays of 3 ints
+int[$] x = [ 0, 1 ]; // x is a static array of 2 ints
+int[$][] x = [[0, 2], [1, 3]]; // x is a dynamic array of static arrays with a length of 2

Reference

None

Copyright & License

Copyright (c) 2020, 2021 by the D Language Foundation

Licensed under Creative Commons Zero 1.0

Reviews

The DIP Manager will supplement this section with a summary of each review stage of the DIP process beyond the Draft Review.