Add LDM notes for 2018-09-10
This commit is contained in:
parent
95b5cf8bf1
commit
52fe9ea7be
132
meetings/2018/LDM-2018-09-10.md
Normal file
132
meetings/2018/LDM-2018-09-10.md
Normal file
|
@ -0,0 +1,132 @@
|
|||
# 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.
|
|
@ -109,6 +109,12 @@ We continued to discuss the range operator in C# and the underlying types for it
|
|||
1. Index operator: is it a unary operator?
|
||||
1. Compiler intrinsics
|
||||
|
||||
## September 10, 2018
|
||||
|
||||
[C# Language Design Notes for September 10, 2018](LDM-2018-09-10.md)
|
||||
|
||||
1. Nullability of constraints in inheritance and interface implementation
|
||||
2. Static local functions
|
||||
|
||||
# Upcoming meetings
|
||||
|
||||
|
|
Loading…
Reference in a new issue