# C# Language Design Notes for September 10, 2018 ## Agenda 1. Nullability of constraints in inheritance and interface implementation 2. Static local functions # Discussion QOTD: *Don't open your mind so much the language falls out* ## Nullability of constraints in overriding In C# we don't allow override methods to re-specify generic constraints. The question then is how to treat constraints that are inherited from a base method with a different `NonNullTypes` attribute. For example: ```C# // Assembly 1 [NonNullTypes(true)] class Base { virtual void M() where T : C? { } } --- // Assembly 2 [NonNullTypes(false)] class Derived : Base { override void M() { } } ``` Does using `T` as a non-null type produce a warning, even though we've said `[NonNullTypes(false)]` in the derived class? **Conclusion** When the base context is `true` and the derived is `false`, suppress related warnings. When the base is false and the derived is true, treat unannotated constraints as oblivious. ### Inheritance and explicit interface implementation Similar to the above case, there's a question about how "sticky" nullability is through interface implementation and inheritance. For instance, the following class uses a constructed inherited member to explicitly implement an interface. Does nullability on the type parameters have to match? Here is the correct implementation: ```C# interface I1 { void M() where U : T } class C : I1 { void I1.M() {} } ``` And what if you remove the question mark in the explicit implementation? ```C# class C : I1 { void I1.M() {} } ``` **Conclusion** If the member and the implementing type share the same `NonNullTypes` context, the annotations must match, so the example directly above that mismatches `C?` with `C` would be an error stating that the class `C` does not implement the interface `I1`. If the `NonNullTypes` context differs and the context on the outside is `false` and the inside is `true`, there is no error or warning about the mismatch, but a warning that `?` is disallowed in `NonNullTypes(false)` context. If the context on the inside is `false` and the `outside` is true, there is also no error or warning, this time because the interior context causes `C` to be treated as oblivious, which can match with `C?`. ## Static local functions Proposal: https://github.com/dotnet/csharplang/issues/1565 We like this proposal. One potentially confusing part is that static local functions cannot capture local variables, even in containing static methods. This is appropriate for the design, and we intend to keep it, but acknowledge that it may be confusing at first. **Q & A** *Q:* If the proposal is accepted we would allow two states to be enforced: all capturing is allowed and no capturing is allowed. Do we want to allow intermediate states with something like capture lists? **A:** No, this is as far as we go. *Q:* Should we allow attributes too? That could be useful for related scenarios, like P/Invoke. **A:** Yes, we liked the idea originally, but it didn't make C# 7.0. We'd like to finalize support for this. *Q:* Should we relax shadowing rules? This isn't strictly related to the proposal, but it seems like the restriction is more draconian with static local functions because you cannot capture variables and instead have to come up with new names if they are being passed as arguments. **A:** We dislike differing shadowing behavior between static and non-static local functions. We're warm to the idea of allowing all local function parameters shadow locals in parent scopes. We're also interested in allowing shadowing in lambdas. We would like to see a separate proposal on this to document the details. *Q:* Can static local functions capture type parameters? **A:** Yes. *Q:* Do we want to allow "static lambdas"? **A:** The value seems much lower since lambdas are usually much shorter. It's also a more intrusive syntax inline to the call. Rejected.