Skip to content

Commit 8a4cc1a

Browse files
committed
Revise null-aware elements proposal.
1 parent 329f626 commit 8a4cc1a

File tree

1 file changed

+41
-33
lines changed

1 file changed

+41
-33
lines changed

working/0323-null-aware-elements/feature-specification.md

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Experiment flag: null-aware-elements
1010

1111
## Introduction
1212

13-
In Dart 2.3, we added [several syntax new features][unified] for use inside
13+
In Dart 2.3, we added [several new syntax features][unified] for use inside
1414
collection literals. You can use `...` to spread the contents of one collection
1515
into another, and `if` and `for` to perform branching and looping control flow
1616
while generating elements.
@@ -62,7 +62,7 @@ have null-aware spreads, but not null-aware single values.
6262

6363
This proposal remedies that by adding *null-aware elements*. Using Lorenzen's
6464
suggested syntax, inside a collection literal, a `?` followed by an expression
65-
includes the value if it's not `null` or discards the `null` otherwise:
65+
includes the value if it's not `null` and discards the `null` otherwise:
6666

6767
```dart
6868
void printThree(String? a, String? b, String? c) {
@@ -142,8 +142,8 @@ general-purpose feature.
142142

143143
It's also certainly the case that my simple analysis didn't catch many other
144144
workarounds that users are using to deal with `null`. (I did look for uses of
145-
`if-case` and `.whereNotNull()` that seemed like could become null-aware
146-
elements but only found a handful.)
145+
`if-case`, `.whereNotNull()`, and `.nonNulls` that seemed like could become
146+
null-aware elements but only found a handful.)
147147

148148
This suggests that if we're to support this feature at all, we should support
149149
it for map entries too. The syntax options, assuming we want to stick with a
@@ -322,7 +322,7 @@ otherNullableThing`.*
322322
expressions, null-aware operators, and null-check patterns. However, I don't
323323
believe there is any ambiguity in this new syntax. The preceding token will
324324
usually be `,`, `[`, `{`, or `:`, none of which can appear before `?` in any
325-
form that uses that character. The `?` may also appear before `)` after the
325+
form that uses that character. The `?` may also appear after `)` after the
326326
header of an `if` or `for` element, or after `else`, but those are also not
327327
ambiguous.*
328328

@@ -356,50 +356,53 @@ To infer the type of `element` in context `P`:
356356

357357
* If `element` is a null-aware `expressionElement` with expression `e1`:
358358

359-
* If `P` is `?`:
359+
* If `P` is `_` (the unknown context):
360360

361-
* Let `u` be the inferred type of the expression `e1` in context `?`.
361+
* Let `U` be the inferred type of the expression `e1` in context `_`.
362362

363363
* Else, `P` is `Set<Ps>`:
364364

365-
* Let `u` be the inferred type of the expression `e1` in context `Ps`.
365+
* Let `U` be the inferred type of the expression `e1` in context
366+
`Ps?`. *The expression has a nullable context type because it may
367+
safely evaluate to `null` even when the surrounding set doesn't
368+
allow that because the `?` will discard a `null` entry.*
366369

367-
* The inferred set element type is **NonNull**(`u`). *The value added to
370+
* The inferred set element type is **NonNull**(`U`). *The value added to
368371
the set will never be `null`.*
369372

370373
* If `element` is a null-aware `mapElement` with entry `ek: ev`:
371374

372-
* If `P` is `?` then the inferred key and value types of `element` are:
375+
* If `P` is `_` then the inferred key and value types of `element` are:
373376

374-
* Let `uk` be the inferred type of `ek` in context `?`.
377+
* Let `Uk` be the inferred type of `ek` in context `_`.
375378

376379
* If `element` is a key null-aware element then the inferred key
377-
element type is **NonNull**(`uk`). *The entry added to the map will
380+
element type is **NonNull**(`Uk`). *The entry added to the map will
378381
never have a `null` key.*
379382

380-
* Else the inferred key element type is `uk`. *The whole element is
383+
* Else the inferred key element type is `Uk`. *The whole element is
381384
null-aware, but the key part is not, so it is inferred as normal.*
382385

383-
* Let `uv` be the inferred type of `ev` in context `?`.
386+
* Let `Uv` be the inferred type of `ev` in context `_`.
384387

385388
* If `element` is a value null-aware element then the inferred value
386-
element type is **NonNull**(`uv`). *The entry added to the map will
389+
element type is **NonNull**(`Uv`). *The entry added to the map will
387390
never have a `null` value.*
388391

389-
* Else the inferred value element type is `uv`. *The whole element is
392+
* Else the inferred value element type is `Uv`. *The whole element is
390393
null-aware, but the value part is not, so it is inferred as normal.*
391394

392395
* If `P` is `Map<Pk, Pv>` then the inferred key and value types of
393396
`element` are:
394397

395398
* If `element` is a key null-aware element then:
396399

397-
* Let `uk` be the inferred type of `ek` in context `Pk?`. *The key
400+
* Let `Uk` be the inferred type of `ek` in context `Pk?`. *The key
398401
expression has a nullable context type because it may safely
399402
evaluate to `null` even when the surrounding map doesn't allow
400403
that because the `?` will discard a `null` entry.*
401404

402-
* The inferred key element type is **NonNull**(`uk`). *The entry
405+
* The inferred key element type is **NonNull**(`Uk`). *The entry
403406
added to the map will never have a `null` key.*
404407

405408
* Else the inferred key element type is the inferred type of `ek` in
@@ -408,12 +411,12 @@ To infer the type of `element` in context `P`:
408411

409412
* If `element` is a value null-aware element then:
410413

411-
* Let `uv` be the inferred type of `ev` in context `Pv?`. *The
414+
* Let `Uv` be the inferred type of `ev` in context `Pv?`. *The
412415
value expression has a nullable context type because it may
413416
safely evaluate to `null` even when the surrounding map doesn't
414417
allow that because the `?` will discard a `null` entry.*
415418

416-
* The inferred value element type is **NonNull**(`uv`). *The entry
419+
* The inferred value element type is **NonNull**(`Uv`). *The entry
417420
added to the map will never have a `null` value.*
418421

419422
* Else the inferred value element type is the inferred type of `ev` in
@@ -430,27 +433,32 @@ null-aware part because `null` won't propagate out.*
430433

431434
Likewise, with list literals, we add a clause to handle a null-aware expression.
432435

433-
To infer the type of `element` in context `P` (which may be `?`):
436+
To infer the type of `element` in context `P`:
434437

435438
* If `element` is null-aware `expressionElement` with expression `e1`:
436439

437-
* Let `u` be the inferred type of `element` in context `P?`. *The
438-
expression has a nullable context type because it may safely evaluate to
439-
`null` even when the surrounding list doesn't allow that because the `?`
440-
will discard a `null` entry.*
440+
* If `P` is `_`:
441+
442+
* Let `U` be the inferred type of the expression `e1` in context `_`.
443+
444+
* Else, `P` is `List<Ps>`:
445+
446+
* Let `U` be the inferred type of the expression `e1` in context
447+
`Ps?`. *The expression has a nullable context type because it may
448+
safely evaluate to `null` even when the surrounding set doesn't
449+
allow that because the `?` will discard a `null` entry.*
441450

442-
* The inferred list element type of `element` is **NonNull**(`u`). *The
443-
value added to the map will never be `null`.*
451+
* The inferred list element type is **NonNull**(`U`). *The value added to
452+
the list will never be `null`.*
444453

445454
### Constants
446455

447-
A null-aware `expressionElement` or `mapElement` is constant or potentially
448-
constant if its inner expression or map entry is constant or potentially
449-
constant, respectively.
456+
A null-aware `expressionElement` or `mapElement` is constant if its inner
457+
expression or map entry is constant.
450458

451-
## Dynamic semantics
459+
## Runtime semantics
452460

453-
The dynamic semantics of collection literals [are
461+
The runtime semantics of collection literals [are
454462
defined][unified-dynamic-element] in terms of recursively building up a *result*
455463
sequence of values (list or set) or map entries (map). For each kind of
456464
`element`, there is specification for how that element adds to the result. We
@@ -525,7 +533,7 @@ use instead:
525533
526534
[
527535
nullableFoo,
528-
].whereNotNull().toList();
536+
].nonNulls;
529537
```
530538

531539
If any of these patterns can be reliably detected through static analysis, then

0 commit comments

Comments
 (0)