
# C# Language Design Meeting for Nov. 11, 2019

## Agenda

1. Confirm removal of warning calling a method that returns `[MaybeNull]T`
2. Allow interpolated string constant
3. Enhancing the Common Type Specification
4. Type pattern
5. Simple name binding with target types

## Discussion

### Calling a method that returns `[MaybeNull]T`

We previously proposed this as a safety warning, since the value of `T` could be nullable,
similar to `default(T)`. The approach of warning on all uses turns out to be more annoying than
we thought, producing multiple false positives.

There are a couple steps to improving it. First, we'd like to not warn if the expression is
returned in a method that is also annotated to return `[MaybeNullT]`. This would require us to
use the information from the nullable attributes (or at least `[MaybeNull]`) inside the method.
We also have to implement a three flow state design for nullable analysis, since it's not good
enough to know whether the flow state is maybe null or not null (since all unconstrained generics
are already considered maybe null), we need to know if the state is maybe null, even if the
substituted generic does not allow null.

**Conclusion**

Confirmed that the warning can be removed. This will make it likely that we will produce more
warnings in the case that all of these component parts are working, but we're hoping that almost
all of these warnings will be real safety issues, not false positives.

### Interpolated string constant

https://github.com/dotnet/csharplang/issues/2951

The simplest form of this proposal is to just allow constant strings with `$` in front of them.
For example,

```C#
const string s = $"abc";
```

This doesn't really seem very useful, except in refactoring where you had an interpolated string,
and made it constant, and it happened to not have any substitution.

A more useful version would allow constant interpolated strings if all of the substitutions are
constant strings.

**Conclusion**

Seems reasonable. We'll put it in "any time". @agocke to champion.

### Enhancing the Common Type Specification (again)

https://github.com/dotnet/csharplang/issues/2823

We discussed a number of improvements, notably using target-typing as a fallback when there is no
common type. The idea to improve target-typing for nullable seems interesting, but we need a more
detailed proposal to examine. There's a worry that this will significantly complicate type
inference, which needs investigation.

There are a few associated questions, namely:

1. Do we improve the common type algorithm to not find a common type if all the component
types cannot be converted to it? (e.g., `1` and `null` would have no common type)

2. Do we allow improve common type inference for the cases where there is no target type (e.g.,
when assigned to `var` or a method that takes a generic `T`)

3. Do we allow target typing when the common type is not convertible to the target? (e.g.,
`byte b = cond ? 1 : 2` would fall back to target typing because `int` is not convertible to
`byte`)

There's also the behavioral difference between the old expressions which have target-typing as a
fallback, and the switch expression, which currently prefers the target-typing if one exists.
Some of the questions above, including (3), would make the two behaviors be very similar, in that
target-typing would be present in the few cases that rely on it.

**Conclusion**

We agree to the following changes:

1. Target-typing as a fallback for the old expressions (array creation, conditional expression, et al.)

2. We want target-typing to succeed in the case where the common type does not convert to the
target-type

3. We want to change switch expression to use the natural type if it converts to the target-type,
and only use target-typing if the natural type does not convert to the target.

We want to continue to investigate improvements to the common type algorithm, including changes
to support nullability.

### Type patterns

https://github.com/dotnet/csharplang/issues/2925

The first proposal is to simplify some existing constructs and add some simplification to some
current behavior by creating a simple "type pattern" without a variable introduction.

```C#
void M(object o1, object o2)
{
    var t = (o1, o2);
    if (t is string) // This is currently legal and we would just change the spec to say that this
                     // is a type pattern, although the `is` would prefer a type in an ambiguity
                     // to preserve backwards compatibility
    if (t is (int, string)) // This would now be legal as a tuple pattern, containing two type patterns
    switch (t)
    {
        case string: // this would now work, but would be the inverse of `is`, preferring a constant
                     // for backwards compatibility
    }
}
```

This has broad agreement as a good change, and multiple LDM members have been frustrated that the
switch statement and expressions often require a `_` in these places.

**Conclusion**

The first proposal, allowing simple type patterns, is broadly useful right now. Accepted for the
C# 9.0 milestone.

### Name lookup for binding simple names with known target type

https://github.com/dotnet/csharplang/issues/2926

The second proposal is to adjust binding with a known target type, so you could say

```C#
class Outer
{
    public class Inner1 : Outer {}
    public class Inner2<T> : Outer {}
}

int M1(Outer o) => o switch
{
    Inner1 _ => 0, // Binds to Outer
    Inner2<int> _ => 1;
}
```

or even

```C#
Color x = b ? Red : Greed;
var y = b ? Color.Red : Greed;
```

**Conclusion**

This change feels especially natural in switch statements and expression with enums. It seems
useful in the other contexts as well. The extension to nested classes would be particularly
relevant to a discriminated union based off of nested classes. 

There's a lot here in the binding changes. Let's sit on it a bit and take a look with a
discriminated unions proposal. Triaged to C# 9.0 to match discriminated unions.
