3.9 KiB
C# Language Design Meeting for Nov. 13th, 2019
Agenda
- Discriminated unions
- 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:
-
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
- No real reason, except worries about inheritance aside from members
-
How
partial
do we want to allow things? There's good reason to put all the members together -
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
-
What if you want to define just regular nested classes, that don't inherit from the root type?
-
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.