csharplang/meetings/2019/LDM-2019-11-13.md
2019-11-15 13:42:02 -08:00

3.9 KiB

C# Language Design Meeting for Nov. 13th, 2019

Agenda

  1. Discriminated unions
  2. Improved analysis of [MaybeNull]T

Discussion

Initial discriminated union proposal

https://github.com/dotnet/csharplang/blob/master/proposals/discriminated-unions.md

Questions around some restrictions:

  1. Why can't you have constructor parameters on the enum class type?

    • No real reason, except worries about inheritance aside from members
      • Keeping inheritance syntactically close by is considered a feature of the proposal, since the user can easy analyze what all the possible children of the root are
    • Syntax for the base call in value members would have to be specified
  2. How partial do we want to allow things? There's good reason to put all the members together

  3. Are records short enough syntax that we don't need the "simple" type syntax?

    • Regardless of brevity, if members are required to explicitly inherit from the root this seems like purely useless work, since doing otherwise would be an error
  4. What if you want to define just regular nested classes, that don't inherit from the root type?

  5. Scoping for nested enum class members? The proposal for altering binding wouldn't help with nested members, because it only applies to simple names.

enum class Expr
{
    enum class BinaryOperator
    {
        Add(Expr left, Expr right),
        Multiply(Expr left, Expr right)
    }
}

Expr M(Expr left, Expr right)
{
    return Add(left, right); // error, no name "Add" found under Expr
}

int M(Expr e) => e switch
{
    Add _ => 0, // error, no name Add found under Expr
}

There's also a proposed alternate syntax that would let you put everything directly into the enum class:

enum class Color
{
    Red,
    Greed; // semicolon delimiting end of enum class cases, and start of regular members

    public static int HelperField;
    public static int HelperProperty => 0;
    public int HelperMethod() => 0;
}

Improved analysis of [MaybeNull]T

Proposal: https://github.com/dotnet/csharplang/issues/2946

The new proposed abstract domain for nullable analysis would be:

enum
{
    NotNull,
    MaybeNull,
    MaybeNullEvenIfNotNullable
}

If we improve analysis of MaybeNull inside the method, do we want to push the new functionality through for all the nullable attributes at the same time? This seems useful from a consumer perspective, in that you get the different warnings all at the same time, but there's also the simple question of resources and scheduling.

Similarly, if we do improve MaybeNull analysis in the body of the method, do we need to improve the analysis in other places, like overriding, at the same time? Or are we OK with a piecemeal state where MaybeNull is enforced in the method body but not in overriding? Or where we enforce MaybeNull in overriding, but not other attributes like DisallowNull?

A broader question is how common MaybeNull is in general. Our experience in the .NET Core mscorlib is that there are only 10 occurrences of MaybeNull, and even when broadening to LINQ, there are at most a few dozen occurrences, mostly in places that may return a default value. In comparison, NotNullIfNotNull has ~30 occurrences in mscorlib.

On the other hand, default(T) is very common and is an instance of MaybeNull in a sense. This implies that the flow state of MaybeNull is particularly important.

An additional question is whether or not to revive the T? proposal to deal with the historical problems around MaybeNull annotations on locals and other places where attributes are not permitted.

Conclusion

We think improving any aspect of the attributes can be considered independently and we will not require the changes to ship together. We think that proposal is good. Accepted.

No statement on T?. We will schedule a discussion soon to get a permanent decision on the proposal.