Skip to content

Latest commit

 

History

History
130 lines (83 loc) · 3.7 KB

LDM-2018-11-05.md

File metadata and controls

130 lines (83 loc) · 3.7 KB

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

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)

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.