# 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<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:

```C#
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?

```C#
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.