
# 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.