Added LDM notes for February 8th, 2021

This commit is contained in:
Fredric Silberberg 2021-02-08 17:09:24 -08:00
parent 6f3b971e45
commit e7fd82ec95
No known key found for this signature in database
GPG key ID: BB6144C8A0CEC8EE
2 changed files with 128 additions and 5 deletions

View file

@ -0,0 +1,118 @@
# C# Language Design Meeting for Feb 8th, 2021
## Agenda
1. Virtual statics in interfaces
1. [Syntax Clashes](#syntax-clashes)
2. [Self-applicability as a constraint](#self-applicability-as-a-constraint)
3. [Relaxed operator operand types](#relaxed-operator-operand-types)
4. [Constructors](#constructor)
## Quote(s) of the Day
- "If you need to kick yourself I see that [redacted] has a foot in the chat you can kick yourself with"
- "Are we at the point where we derail your meeting with other proposals?"
- "It's the classic, noble art of retconning"
## Discussion
Today, we want to take a look at a few top-level design decisions for virtual statics in interfaces that will drive further design and implementation
decisions for this feature.
### Syntax Clashes
C# 8 brought 2 new features to interfaces: default members, and non-virtual static members. This sets up a clash between static virtual members and
static non-virtual members. In pre-C# 8, `interface` members were always virtual and abstract. C# 8 blurred the line here: private and static members
in interfaces are non-virtual. For private members, this makes perfect sense, as the concept of a virtual private method is an oxymoron: if you can't
see it, you can't override it. For statics, it's a bit more unfortunate because we now have inconsistency in the default-virtualness of members in
the interface. We have a few options for addressing this inconsistency:
1. Accept life as it is. We'd require `abstract` and/or `virtual` on static members to mark them as such. There is some benefit here: `static` has
meant something for 21 years in C#, and that is not `virtual`. Requiring a modifier means this does not change.
2. Break the world. Make static members in interfaces mean static virtual by default. This gets us consistency, but breaks consumers in some fashion
and/or introduces multiple dialects of C# to support.
3. We could introduce a bifurcation in interfaces with a `virtual` modifier on the `interface` declaration itself. When marked with `virtual`, `static`
members of the interface are automatically `virtual` by default. This is very not C#-like: we require `static` on all members of `static class`es, why
would `virtual interface`s be any different here? And how would you define the existing non-`virtual` members in such an interface?
Options 2 and 3 also have a question of how they will apply to class members. Due to the size of the changes required we may have to split virtual
static members, shipping with just interfaces in the first iteration and adding class types at a later point. However, we need to make sure that we
design the language side of these changes together, so when class virtual statics are added they don't feel like an afterthought. The second and third
proposals would likely need to have the first proposal for the class version of the feature anyway. While it would be consistent with instance members,
neither of them would totally eliminate the needs to apply the modifiers to interface members.
#### Conclusion
We will require `abstract` or `virtual` be applied to a virtual static member. We will also look at allowing these modifiers for intstance interface
methods, even though they are redundant, much like we allow `public` on members today.
### Self-applicability as a constraint
`abstract` static members introduce an interesting scenario in which an interface is no longer valid as a substitute for a type parameter constrained
to that interface type. Consider this scenario:
```cs
interface IHasStatics
{
abstract static int GetValue(); // No implementation of GetValue here
}
class C : IHasStatics
{
static int GetValue() => 0;
}
void UseStatics<T>() where T : IHasStatics
{
int v = T.GetValue();
}
UseStatics<C>(); // C satisfies constraint
UseStatics<IHasStatics>(); // Error: IHasStatics doesn't satisfy constraint
```
The main question here is what do we do about this? We have 2 paths:
1. Forbid interfaces with an abstract static from satisfying a constraint on itself.
2. Forbid access to static virtuals with a type parameter unless you have an additional constraint like `concrete`.
Option 2 seems weird here. Why would a user have constrained to a type that implements an interface, rather than just taking the interface, unless
they wanted to use these methods? Yes, adding an `abstract static` method to an interface where one does not exist today would be a breaking change
for consumers, but that's nothing new: that's why we added DIMs in the first place, and it would continue to be possible to avoid the break by providing
a default method body for the virtual method, instead of making it abstract.
#### Conclusion
We choose option 1.
### Relaxed operator operand types
Today, C# requires that at least one of the operand-types of a user-defined operator be the current type. This breaks down with user-defined virtual
operators in interfaces, however, as the type in the operator won't be the current type, it will be some type derived from the current type. Here,
we naturally look at self types as a possible option. We are concerned with the amount of work that self-types will require, however, and aren't sure
that we want to tie the shipping of virtual statics to the need for self types (and any other associated-type feature). We also need to make sure that
we relax operators enough, and define BCL-native interfaces in a way, such that asymmetric types are representable. For example, a matrix type would
want to be able to add a matrix and a numeric type, and return a matrix. Or `byte`'s `+` operator, which does not return a `byte` today. Given that,
we think it is alright to ship this feature and define a set of operator interfaces without the self type, as we would likely be forced to not use it
in the general interfaces anyway to keep them flexible enough for all our use cases.
#### Conclusion
We're ok with relaxing the constraints as much as we need to here. We won't block on self types being in the language.
### Constructors
Finally, we looked at allowing or disallowing constructors as virtual in interfaces. This is an interesting area: either derived types would be required
to provide a constructor that matches the interface, or derived types would be allowed to not implement interfaces that their base types do. The feature
itself is a parallel to regular static methods; in order to properly describe it in terms of static methods, you'd need to have a self type, which is
what makes it hard to describe in today's C# terms in the first place. Adding this also brings in the question of what do we do about `new()`? This may
be an area where we should prefer a structural approach over a nominal approach, or add a form of type classes to the language: if we were to effectively
deprecate `new()`, that would mean that every type that has a parameterless constructor would need to implement an `IHasConstructor` interface instead.
And we would need to have infinite variations of that interface, and add them to every type in the BCL. This would be a serious issue, both in terms of
sheer surface area required and in terms of effect on type loads and runtime performance penalties for thousands and thousands of new types.
#### Conclusion
We will not have virtual constructors for now. We think that if we add type classes (and allow implementing a type class on a type the user doesn't own),
that will be a better place for them. If we want to improve the `new()` constraint in the mean time, we can look at a more structural form, and users
can work around the lack of additional constraints for now by using a static virtual.

View file

@ -43,15 +43,20 @@ First class native integer support - https://github.com/dotnet/csharplang/issues
- Global usings
- *Triage championed features and milestones*
## Feb 8, 2021
- Statics in interfaces
# C# Language Design Notes for 2021
Overview of meetings and agendas for 2021
## Feb 8, 2021
[C# Language Design Notes for February 8th, 2021](https://github.com/dotnet/csharplang/blob/master/meetings/2021/LDM-2021-02-08.md)
1. Virtual statics in interfaces
1. Syntax Clashes
2. Self-applicability as a constraint
3. Relaxed operator operand types
4. Constructors
## Feb 3, 2021
[C# Language Design Notes for February 3rd, 2021](https://github.com/dotnet/csharplang/blob/master/meetings/2021/LDM-2021-02-03.md)