# C# Language Design Meeting for Jan. 6, 2020 ## Agenda 1. Use attribute info inside method bodies 1. Making Task-like types covariant for nullability 1. Casting to non-nullable reference type 1. Triage ## Discussion ### Use attribute info inside method bodies Examples: 1. ```C# bool TryGetValue([MaybeNullWhen(false)]out T t) { return other.TryGetValue(out t); // currently warns } ``` 2. ```C# [return: MaybeNull] T GetFirstOrDefault() { return null; // currently warns } ``` 3. Overriding/implementation ```C# class A { [return: MaybeNull] virtual T M(); } class B : A { override string? M(); // warns about no [MaybeNull] } ``` We don't have a complete design here, but some cases have an intuition about the correct behavior. In overriding, specifically, we need a specification for what it means for an annotation to be "compatible" with each of the attributes. On the other hand, it's not clear what the behavior of `MaybeNullWhenTrue` should be in all cases. **Conclusion** We'd like to do this if the return on investment seems worth it, but to fully evaluate we need a proposal of the work. ### Making Task-like objects nullable covariant This is a pretty common pain-point, and it's not the first time we special-cased variance, specifically `IEquatable` is treated as nullable contravariant. It's unfortunate that the CLR doesn't have capability to make `Task` full covariant, but handling even nullable alone would be useful. Moreover, if we later get the capability to mark `Task` covariant, this would not harm the effort. We also think that there may be some special cases introduced for overload resolution where we consider `Task` as covariant already. If we could reuse that knowledge, that would be useful. **Conclusion** Let's see if we can dig up the overload resolution changes for Task-like types and try to adapt the same rule for making Task-like types nullable covariant. ### Casting to non-nullable reference type Example: ```C# BoundNode? node = ...; if (node.Kind == BoundKind.Expression) { var x = (BoundExpression)node; // warning if node is nullable } ``` The question is if this warning is valuable, or annoying. We've hit this most often in Roslyn when using the pattern `(object)x == null` to do a null check while avoiding the user-defined equality check. This is annoying in the Roslyn codebase, but not very common outside it. On the other hand, there's feeling that when doing the BoundNode to BoundExpression check, which is less common in Roslyn but more common generally, there's agreement that the warning is useful in making the type annotated with the most accurate representation of the null state. **Conclusion** Keep the warning, no change. We think the warning is valuable for the non-null-check cases. Newer version of C# have features that address the null check problem and Roslyn should move to use `x is null` or similar. ## Triage Three related proposals: #3037, #3038, #377. These all deal with the general problem of statements in expressions, especially statements in switch expressions, and switch expression form in statements. They don't necessarily require each other, but they fit a lot of the same syntax and semantic space, so we should consider them all together. There's also a sketch for how we could unify the syntax forms of all of three proposals, with potential syntax changes. **Conclusion** We agree that all of these proposals are addressing important scenarios, and some improvement here is valuable. We're not sure where we want to go with generalized statements-in-expressions vs. adding special syntax forms for switch expression/statement. We're mainly concerned that if we do switch expression blocks, we want to make sure that the we don't block a future generalization to all expressions. We need to find a generalization that we like, reject a generalization and accept this syntax, or put these improvements on the back-burner if we think that a generalization is possible, we just haven't found it. Accepted for C# 9.0 investigation.