csharplang/meetings/2018/LDM-2018-09-10.md
2018-09-21 13:59:04 -07:00

3.9 KiB

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:

// Assembly 1
[NonNullTypes(true)]
class Base
{
    virtual void M<T>() where T : C?
    { }
}

---
// Assembly 2

[NonNullTypes(false)]
class Derived : Base
{
    override void M<T>()
    { }
}

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:

interface I1<T>
{
    void M<U>() where U : T
}

class C : I1<C?>
{
    void I1<C?>.M<X>() {}
}

And what if you remove the question mark in the explicit implementation?

class C : I1<C?>
{
    void I1<C>.M<X>() {}
}

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<C?>.

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.