130 lines
3.7 KiB
Markdown
130 lines
3.7 KiB
Markdown
|
|
||
|
# C# Language Design Notes for Nov 5, 2018
|
||
|
|
||
|
## Agenda
|
||
|
|
||
|
1. Where can #nullable go?
|
||
|
2. Open issues with pattern matching
|
||
|
|
||
|
## Discussion
|
||
|
|
||
|
### Where can you put `#nullable`?
|
||
|
|
||
|
*Q: Does `#nullable` appear in metadata in any way?*
|
||
|
|
||
|
It may be useful to minimize the amount of extra metadata by putting it on
|
||
|
containers (like types) and letting the context flow down. However, this
|
||
|
becomes complex when considering things like `partial`. In general, we don't
|
||
|
want to let the implementation decide the language support and we would
|
||
|
prefer to limit things only if it improves the language experience, not makes
|
||
|
implementation easier.
|
||
|
|
||
|
Instead, we'll start by where it makes sense to allow `#nullable` for the
|
||
|
language.
|
||
|
|
||
|
*Q: If we were to allow it anywhere, where does it span?*
|
||
|
|
||
|
One proposal is the last token in the type syntax. So
|
||
|
|
||
|
```C#
|
||
|
Dictionary<string,
|
||
|
#nullable disable
|
||
|
string>
|
||
|
#nullable enable
|
||
|
```
|
||
|
|
||
|
specifies the nullable context for the second `string` and the context for
|
||
|
`Dictionary<string, string>`.
|
||
|
|
||
|
*Q: If we believe that the least restrictive version is a reasonable design, what
|
||
|
makes sense from an implementation perspective?*
|
||
|
|
||
|
Basing the context on the end type token is a reasonable design for
|
||
|
implementation. If we decide that this causes significant extra metadata to
|
||
|
be generated, we can provide optimizations at emit time without changing the
|
||
|
semantics of the language.
|
||
|
|
||
|
**Conclusion**
|
||
|
|
||
|
Basing the nullable context on the last token in the pragma region actually
|
||
|
makes a lot of sense. Let's go ahead with that as the current plan.
|
||
|
|
||
|
For warnings, we would base it entirely on diagnostic locations, which is
|
||
|
what we do for pragma suppression right now.
|
||
|
|
||
|
### Misc. Nullable
|
||
|
|
||
|
*Proposal: Do not allow nullable on the right of a using alias*
|
||
|
|
||
|
Accepted.
|
||
|
|
||
|
*Q: What about `typeof` and `nameof`?*
|
||
|
|
||
|
Same behavior as nullable value types (allowed in `typeof`, not in `nameof`).
|
||
|
|
||
|
### Pattern matching
|
||
|
|
||
|
#### Deconstruction and ITuple
|
||
|
|
||
|
*Proposal:*
|
||
|
|
||
|
1. If the type is a tuple type (any arity >1; see below) then use tuple semantics
|
||
|
2. If the type has no accessible instance Deconstruct and satisfies the `ITuple`
|
||
|
deconstruct constraints, use `ITuple` semantics
|
||
|
3. Otherwise attempt `Deconstruct` semantics (instance or extension)
|
||
|
|
||
|
Arguments against:
|
||
|
|
||
|
- Exhaustiveness gets better with an extension Deconstruct
|
||
|
- Different behavior between pattern matching and deconstruction
|
||
|
- But the extension and ITuple implementation should be semantically equivalent
|
||
|
- Boxes in the case of no instance Deconstruct and an explicit ITuple implementation
|
||
|
- But pattern matching boxes anyway for everything except a concrete value type
|
||
|
|
||
|
Arguments for:
|
||
|
|
||
|
- We don't have to add complex rules about which extensions are applicable
|
||
|
|
||
|
|
||
|
*Alternative Proposal:*
|
||
|
|
||
|
1. If the type is a tuple type (any arity >1; see below) then use tuple semantics
|
||
|
2. If "binding" a Deconstruct invocation finds one or more applicable methods,
|
||
|
use Deconstruct.
|
||
|
3. If the type satisfies the `ITuple` deconstruct constraints, use `ITuple`
|
||
|
|
||
|
**Conclusion**
|
||
|
|
||
|
We like the alternative more, but very slightly.
|
||
|
|
||
|
#### Pattern matching with 0 and 1 elements
|
||
|
|
||
|
*Proposal:*
|
||
|
|
||
|
Permit pattern-matching tuple patterns with 0 and 1 elements (appropriately
|
||
|
disambiguated as previously decided)
|
||
|
|
||
|
```C#
|
||
|
if (e is ()) ...
|
||
|
|
||
|
if (e is (1) _) ...
|
||
|
if (e is (x: 1)) ...
|
||
|
if (e is (1, 2)) ...
|
||
|
```
|
||
|
|
||
|
The primary concern here is that these disambiguations are impossible in deconstructing
|
||
|
declarations and deconstructing assignments. However, we think that's a fine limitation,
|
||
|
since there are simple workarounds in all of those contexts. Pattern matching, however,
|
||
|
has no such workaround.
|
||
|
|
||
|
**Conclusion**
|
||
|
|
||
|
Accepted.
|
||
|
|
||
|
*Proposal:*
|
||
|
|
||
|
Consider `System.ValueTuple` and `System.ValueTuple<T>` to be tuple types. No syntax changes.
|
||
|
|
||
|
**Conclusion**
|
||
|
|
||
|
Accepted.
|