Skip to content

Add support for nullable arrays nullables #1287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: draft-v8
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions standard/arrays.md
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ The element type of an array can itself be an array type ([§17.2.1](arrays.md#1
>
> <!-- Example: {template:"code-in-main-without-using", name:"PascalArrayDeclarations"} -->
> ```csharp
> int[][] pascals =
> int[][] pascals =
> {
> new int[] {1},
> new int[] {1, 1},
@@ -46,9 +46,18 @@ In effect, the *rank_specifier*s are read from left to right *before* the final

> *Example*: The type in `T[][,,][,]` is a single-dimensional array of three-dimensional arrays of two-dimensional arrays of `int`. *end example*

At run-time, a value of an array type can be `null` or a reference to an instance of that array type.
An array type is a reference type and therefore can be a nullable reference type ([§8.9.3](types.md#893-nullable-reference-types)). Likewise the element type of an array can be a nullable reference type or a nullable value type ([§8.3.12](types.md#8312-nullable-value-types)):

> *Note*: Following the rules of [§17.6](arrays.md#176-array-covariance), the value may also be a reference to a covariant array type. *end note*
- An array type of the form `T[R]` is a non-nullable array with rank `R` and a non-array non-nullable element type `T`.
- An array type of the form `T[R]?` is a nullable array with rank `R` and a non-array non-nullable element type `T`.
- An array type of the form `T?[R]` is a non-nullable array with rank `R` and a non-array nullable element type `T`.
- An array type of the form `T?[R]?` is a nullable array with rank `R` and a non-array nullable element type `T`.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens with arrays of arrays? For example, are all of the following valid - and more importantly, are they all correctly described here?

string[][]
string?[][]
string[]?[]
string[][]?
string?[]?[]
string?[][]?
string[]?[]?
string?[]?[]?

It looks like they're all allowed, and they do make sense. I suspect it all just drops out in terms of the grammar - but I wonder whether just a single example (maybe string?[][]?) would be useful in a note?

At run-time, a value of an array type can be:

- `null`; or
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether it would be useful to have a note either here or in array creation expressions to warn that code that looks safe still can easily be null-unsafe with arrays:

string[] x = new string[5];
int y = x[0].Length;

... no warnings, but will fail at run-time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jskeet – Well there were no warnings from the current version of whatever compiler you used, but there is not reason why some compiler couldn’t issue a warning… I suggest you spin this off as a seperate issue.

- a reference to an instance of that array type; or
- a reference to an instance of a covariant array type, if by [§17.6](arrays.md#176-array-covariance) such exists.

### 17.2.2 The System.Array type

@@ -132,15 +141,15 @@ Because of array covariance, assignments to elements of reference type arrays in
> ```csharp
> class Test
> {
> static void Fill(object[] array, int index, int count, object value)
> static void Fill(object[] array, int index, int count, object value)
> {
> for (int i = index; i < index + count; i++)
> {
> array[i] = value;
> }
> }
>
> static void Main()
> static void Main()
> {
> string[] strings = new string[100];
> Fill(strings, 0, 100, "Undefined");
@@ -169,7 +178,7 @@ array_initializer
variable_initializer_list
: variable_initializer (',' variable_initializer)*
;

variable_initializer
: expression
| array_initializer
48 changes: 30 additions & 18 deletions standard/types.md
Original file line number Diff line number Diff line change
@@ -57,16 +57,6 @@ array_type
: non_array_type rank_specifier+
;

non_array_type
: value_type
| class_type
| interface_type
| delegate_type
| 'dynamic'
| type_parameter
| pointer_type // unsafe code support
;

rank_specifier
: '[' ','* ']'
;
@@ -83,6 +73,28 @@ nullable_type_annotation
: '?'
;

non_array_type
: non_array_reference_type
| value_type
| type_parameter
| pointer_type // unsafe code support
;

non_array_reference_type
: non_nullable_non_array_reference_type
| nullable_non_array_reference_type
;

nullable_non_array_reference_type
: non_nullable_non_array_reference_type nullable_type_annotation
;

non_nullable_non_array_reference_type
: class_type
| interface_type
| delegate_type
| 'dynamic'
;
```

*pointer_type* is available only in unsafe code ([§23.3](unsafe-code.md#233-pointer-types)). *nullable_reference_type* is discussed further in [§8.9](types.md#89-reference-types-and-nullability).
@@ -201,11 +213,11 @@ floating_point_type
tuple_type
: '(' tuple_type_element (',' tuple_type_element)+ ')'
;

tuple_type_element
: type identifier?
;

enum_type
: type_name
;
@@ -327,7 +339,7 @@ C# supports nine integral types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uin
- The `ulong` type represents unsigned 64-bit integers with values from `0` to `18446744073709551615`, inclusive.
- The `char` type represents unsigned 16-bit integers with values from `0` to `65535`, inclusive. The set of possible values for the `char` type corresponds to the Unicode character set.
> *Note*: Although `char` has the same representation as `ushort`, not all operations permitted on one type are permitted on the other. *end note*

All signed integral types are represented using two’s complement format.

The *integral_type* unary and binary operators always operate with signed 32-bit precision, unsigned 32-bit precision, signed 64-bit precision, or unsigned 64-bit precision, as detailed in [§12.4.7](expressions.md#1247-numeric-promotions).
@@ -539,7 +551,7 @@ type_argument_list

type_arguments
: type_argument (',' type_argument)*
;
;

type_argument
: type
@@ -925,10 +937,10 @@ A compiler can update the null state of a variable as part of its analysis.
> int length = p.Length; // Warning: p is maybe null
>
> string s = p; // No warning. p is not null
>
>
> if (s != null)
> {
> int l2 = s.Length; // No warning. s is not null
> int l2 = s.Length; // No warning. s is not null
> }
> int l3 = s.Length; // Warning. s is maybe null
> }
@@ -1031,11 +1043,11 @@ A compiler may use any expression that dereferences a variable, property, or eve
> public class C
> {
> private C? child;
>
>
> public void M()
> {
> _ = child.child.child; // Warning. Dereference possible null value
> var greatGrandChild = child.child.child; // No warning.
> var greatGrandChild = child.child.child; // No warning.
> }
> }
> ```
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Sample: Arrays of NRT

Samples for nullable arrays, arrays of nullables, and nullable arrays of nullables.
Loading