Skip to content

Different reference types: nullable and non-nullable #1124

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

Merged
merged 33 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ec21ebf
Port text from #700
BillWagner May 9, 2024
1bb01bc
fix build warnings
BillWagner May 9, 2024
952ecd4
Revert "fix build warnings"
BillWagner May 9, 2024
bf50416
test for nullable annotations
BillWagner May 9, 2024
9705efa
fix NRT grammar
BillWagner May 9, 2024
a5a576b
revert non-type changes.
BillWagner May 10, 2024
096b2d2
In progress draft
BillWagner May 10, 2024
85e7de5
Edit pass
BillWagner May 14, 2024
b2b3f44
Apply suggestions from code review
BillWagner May 29, 2024
aa0eddc
remove null-oblivious type
BillWagner May 29, 2024
40a7542
a fair amount of cleanup
BillWagner May 30, 2024
ab407b5
fix build issues.
BillWagner May 30, 2024
f392862
fix preprocessor symbols and test messages
BillWagner May 31, 2024
e30a2c4
one more warning fix.
BillWagner May 31, 2024
41b94fd
respond to feedback.
BillWagner Jun 4, 2024
15f86c4
respond to feedback.
BillWagner Jun 10, 2024
d9708f4
Apply suggestions from code review
BillWagner Jul 10, 2024
ae79451
Notes for next updates
BillWagner Jul 11, 2024
9714bda
fix warnings
BillWagner Jul 11, 2024
86f7a1e
rebase and warnings
BillWagner Jul 11, 2024
753016f
word converter warnings
BillWagner Jul 11, 2024
f0312c6
word converter fx
BillWagner Jul 11, 2024
04c2dbf
fix merge issues
BillWagner Sep 16, 2024
2683a1c
Updates from September meeting
BillWagner Sep 16, 2024
ca302d7
typo
BillWagner Sep 16, 2024
346a776
lint issue
BillWagner Sep 17, 2024
a2e91fa
Add description of the `!` operator
BillWagner Sep 18, 2024
ee9e9b9
null forgiveness can't be on array creation
BillWagner Sep 18, 2024
e0c55b4
Update for implicit declarations
BillWagner Sep 18, 2024
2fb0aa2
Apply suggestions from code review
BillWagner Oct 2, 2024
f09154c
final updates from Oct 2nd meeting
BillWagner Oct 7, 2024
0a03e8e
Merge branch 'draft-v8' into nullable-type-definitions
BillWagner Oct 7, 2024
9fc311f
Apply suggestions from code review
BillWagner Oct 8, 2024
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
10 changes: 5 additions & 5 deletions standard/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@ The behavior of the garbage collector can be controlled, to some degree, via sta
> {
> static void Main()
> {
> B? b = new B(new A());
> B b = new B(new A());
> b = null;
> GC.Collect();
> GC.WaitForPendingFinalizers();
Expand Down Expand Up @@ -1075,19 +1075,19 @@ The behavior of the garbage collector can be controlled, to some degree, via sta
>
> class B
> {
> public A? Ref;
> public A Ref;
>
> ~B()
> {
> Console.WriteLine("Finalize instance of B");
> Ref?.F();
> Ref.F();
> }
> }
>
> class Test
> {
> public static A? RefA;
> public static B? RefB;
> public static A RefA;
> public static B RefB;
>
> static void Main()
> {
Expand Down
1 change: 1 addition & 0 deletions standard/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ However, dynamic conversions ([§10.2.10](conversions.md#10210-implicit-dynamic-
An identity conversion converts from any type to the same type or a type that is equivalent at runtime. One reason this conversion exists is so that a type `T` or an expression of type `T` can be said to be convertible to `T` itself. The following identity conversions exist:

- Between `T` and `T`, for any type `T`.
- Between `T` and `T?` for any reference type `T`.
- Between `object` and `dynamic`.
- Between all tuple types with the same arity, and the corresponding constructed `ValueTuple<...>` type, when an identity conversion exists between each pair of corresponding element types.
- Between types constructed from the same generic type where there exists an identity conversion between each corresponding type argument.
Expand Down
42 changes: 42 additions & 0 deletions standard/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,7 @@ Primary expressions include the simplest forms of expressions.
primary_expression
: primary_no_array_creation_expression
| array_creation_expression
| null_forgiving_expression
;

primary_no_array_creation_expression
Expand Down Expand Up @@ -1821,6 +1822,47 @@ A *null_conditional_member_access* expression `E` is of the form `P?.A`. The me

A *null_conditional_projection_initializer* is a restriction of *null_conditional_member_access* and has the same semantics. It only occurs as a projection initializer in an anonymous object creation expression ([§12.8.16.7](expressions.md#128167-anonymous-object-creation-expressions)).

### §Null-Forgiving-Expressions Null-forgiving expressions

This operator sets the null state (§Nullabilities-And-Null-States) of the operand to “not null”.

```ANTLR
null_forgiving_expression
: primary_no_array_creation_expression suppression
;

suppression
: '!'
;
```

This operator has no runtime effect; it evaluates to the result of its operand, and that result retains that operand’s classification.

The null-forgiving operator is used to declare that an expression not known to be a value type is not null.

> *Example*: Consider the following:
>
> <!-- Example: {template:"code-in-partial-class", name:"NullForgivingExpressions", additionalFiles:["PersonWithName.cs", "SupportNullForgivingExpressions.cs"]} -->
> <!-- FIX: create and add 2 files. -->
> ```csharp
> #nullable enable
> public static void M()
> {
> Person? p = Find("John"); // returns Person?
> if (IsValid(p))
> {
> Console.WriteLine($"Found {p!.Name}"); // p can't be null
> }
> }
>
> public static bool IsValid(Person? person) =>
> person != null && person.Name != null;
> ```
>
> If `IsValid` returns `true`, `p` can safely be dereferenced to access its `Name` property, and the “dereferencing of a possibly null value” warning can be suppressed using `!`. *end example*

The null state (§Nullabilities-And-Null-States) of a *null_forgiving_expression* is “not null.”

### 12.8.9 Invocation expressions

#### 12.8.9.1 General
Expand Down
2 changes: 1 addition & 1 deletion standard/lexical-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -1078,8 +1078,8 @@ The following pre-processing directives are available:
- `#line`, which is used to control line numbers emitted for errors and warnings ([§6.5.8](lexical-structure.md#658-line-directives)).
- `#error`, which is used to issue errors ([§6.5.6](lexical-structure.md#656-diagnostic-directives)).
- `#region` and `#endregion`, which are used to explicitly mark sections of source code ([§6.5.7](lexical-structure.md#657-region-directives)).
- `#pragma`, which is used to specify optional contextual information to a compiler ([§6.5.10](lexical-structure.md#6510-pragma-directives)).
- `#nullable`, which is used to specify the nullable context ([§6.5.9](lexical-structure.md#659-nullable-directive)).
- `#pragma`, which is used to specify optional contextual information to a compiler ([§6.5.10](lexical-structure.md#6510-pragma-directives)).

A pre-processing directive always occupies a separate line of source code and always begins with a `#` character and a pre-processing directive name. White space may occur before the `#` character and between the `#` character and the directive name.

Expand Down
2 changes: 1 addition & 1 deletion standard/statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ implicitly_typed_local_variable_declarator
;
```

An *implicity_typed_local_variable_declaration* introduces a single local variable, *identifier*. The *expression* or *variable_reference* shall have a compile-time type, `T`. The first alternative declares a variable with type `T` and an initial value of *expression*. The second alternative declares a ref variable with type `ref T` and an initial value of `ref` *variable_reference*.
An *implicity_typed_local_variable_declaration* introduces a single local variable, *identifier*. The *expression* or *variable_reference* shall have a compile-time type, `T`. The first alternative declares a variable with an initial value of *expression*; its type is `T?` when `T` is a non-nullable reference type, otherwise its type is `T`. The second alternative declares a ref variable with an initial value of `ref` *variable_reference*; its type is `ref T?` when `T` is a non-nullable reference type, otherwise its type is `ref T`.

> *Example*:
>
Expand Down
Loading
Loading