csharplang/meetings/2019/LDM-2019-11-11.md
2019-11-14 15:28:43 -08:00

5.9 KiB

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,

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.

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

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

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.