Added LDM Notes for October 25th, 2021

This commit is contained in:
Fredric Silberberg 2021-10-25 15:43:12 -07:00
parent ec01d26c47
commit 2802e29f4c
No known key found for this signature in database
GPG key ID: 5D1C0E06CE5CD929
2 changed files with 111 additions and 5 deletions

View file

@ -0,0 +1,104 @@
# C# Language Design Meeting for October 25th, 2021
## Agenda
1. [Required members](#required-members)
2. [Delegate type argument improvements](#delegate-type-argument-improvements)
## Quote of the Day
- "It's officially late, not casually late"
## Discussion
### Required members
https://github.com/dotnet/csharplang/issues/3630
It's been nearly a year since we last looked at required members, so we started today by recaping the proposal as it currently
[exists](https://github.com/dotnet/csharplang/blob/ec01d26c47d8d3e3e10b1dd0ade96dae6f99934a/proposals/required-members.md). We also
took a look at the feedback we received when this was last shown to our design review team (mainly internal partners and former
language design members who aren't involved the day-to-day design of the language anymore). The feedback we received at that point
was that the proposal, as it currently stands, is too complex. We have a lot of syntax for enabling a set of contract modifications:
1. Users can say `init(Prop)` to signal that the constructor requires all things the type does, except the members in the `init` clause.
2. Users can say `init required` to signal that the constructor does not require any of the members the type does, and the compiler
will ensure that the user correctly initializes all members in that constructor.
3. Users can say `init required!` to signal the same 2, except that the compiler will not enforce that the user correctly initializes
all members in that constructor.
This syntax was quite specialized, as we intended it to be extensible enough that future work around factories would be able to take
advantage of the same syntax. However, upon coming back to the syntax, we have several people that changed their opinions on the form;
some of the people that didn't originally feel like the syntax "clicked" now like it, and others that originally liked it now think that
it doesn't work well. We took a look at the concrete cases that will want to use the above modifications:
* Copy constructors will want to opt out of the entire contract, as their job is to initialize all the fields to the original instance's
values.
* Types might have a grow-up story, where they may originally ship with just some number of required properties, but later may want to add
a convenience constructor that sets a few common properties. We think that this case, while not unreasonable, is not the common case for
this feature.
The first use case wants at least contract modification 3, and possibly 2 as well. It does not need 1. The second case needs contract
modification 1 to be expressible in C#. Given this, we think that there's a gradual approach we can take to introducing contract
modifications to the language. A potential first approach is just introducing modification 3, without any constructor body validation.
A later version of the language can, as part of a warning wave, turn on body validation, and then later allow individual member exceptions
as in modification 1. We are a bit split on this decision, however. We think a prototype to play around with that implements this initial
decision should help inform the initial feature set we want to ship for this feature. One thing we definitely don't want to do is ship
without constructor body validation and without feeling like we can make that the default state later via a warning wave, as that would
leave us in a bad position where validation is available, but off by default.
We also looked at different syntax forms, namely attributes. We'd considered attributes previously in the design, but steered away from
them to see what we could do with language-integrated syntax. We think we've gone as far down that road as we can, but our final design
still doesn't feel quite right. Given that, we think that having an attribute to express the contract modifications will serve us well.
It can be named more verbosely, should still be able to apply to factory methods, and required no new syntax for users to learn.
Finally, we also considered a couple of other questions:
* Should we have a new accessor, `req`, that is used for a required property instead of `init`?
* We think that this use case is too small, cuts out required setters, and cuts out the ability to mark fields as required.
* Should we use a warning or error on construction? Traditionally, "suppressions" correspond to warnings, and the contract modifications
can be viewed as suppressing the need to initialize things.
* They're not really suppressions though. It's changing the semantics of the code, so we think it's fine (and safer) for us to use
errors on construction, not warnings.
* We haven't considered how required members will interact with `default(StructType)`. Some thought needs to be put into that.
#### Conclusion
We will start working on an implementation of the simplified version of this proposal that uses attributes for contract modifications,
not specific syntax, and only has contract modification 3. Feedback will then inform whether we need 2 or 1 before we ship.
### Delegate type argument improvements
https://github.com/dotnet/csharplang/issues/5321
A couple of weeks ago, Microsoft held our annual internal hackathon, and one of the ideas that we worked on for the it this year was
relaxing type argument restrictions, specifically for delegate types. This would allow delegate types such as `Action<void>` or
`Action<in int, ref readonly Span<char>>`, where these types are restricted from use in delegate types today. In general, the LDM has
a lot of interest in this space, but there is some concern that this proposal doesn't go far enough in relaxing restrictions, and might
run into issues if we try to generalize it more fully. A very common pattern in generic code in C# is to further abstract over parameter
types: for example, a method might take a `Func<T, bool>` and a `T`, and pass the `T` parameter to the `Func<T, bool>` invocation. This
proposal falls apart for such methods, which is a very early cliff to fall over. If we can instead generalize this work, such that these
restricted types are allowed in more places, then we'd be in a much better position. Even if we don't ship the whole thing at once, we'd
really like to make sure we're not painting ourselves into a hole with a proposal like this.
As a part of this, we also want to explore a revamp to the .NET delegate story. Today, `Action` and `Func` are the de-facto delegate types
in C#: they're used throughout the BCL and lambdas/method groups use them where possible for their natural type. However, there are limits
to this, as custom delegate types still have some advantages:
* Ref kinds/restricted type arguments. This is solved by the current proposal as it stands.
* Parameter names. We don't think this would be very difficult to solve, as we have prior art with tuple names.
* Attributes. This is much more difficult to accomplish, to avoid needing to synthesize custom delegate types we'd need to have some way of
putting attributes on a type argument. The runtime does not support this today, and it won't be as simple to add as the type restriction
removals were.
We've been moving towards structural typing of delegates ever since `Action` and `Func` were introduced, and we think it might be a better
approach to the problem to start from fully structural delegate types, and work backwards to see how we could make that work. It's very
likely that we'd end up doing some of the same work generalizing on `Action` and `Func`, but there's some additional interesting wrinkles
around `Action` and `Func<void>`. We might be able to unify these two, but we then want to be able to do the same for other types. How
would we make it work for `Task` and `Task<void>`, for example? Is there some attribute we could add to the runtime that would allow it
to treat these types as identical, forwarding from one to the other? And how would that flow through the C# type system?
#### Conclusions
We don't have any conclusions today. We think that much more exploration of this space is needed before moving forward with any specific
proposal. We want to look into generalizing the generic restriction removals, and into generalized structural typing for delegates.

View file

@ -28,15 +28,17 @@ All schedule items must have a public issue or checked in proposal that can be l
- Utf8 strings (Jared): _writeup in the works_
- Primary constructors and readonly fields feedback (Fred, Cyrus): https://github.com/dotnet/csharplang/discussions/5314
## Oct 25, 2021
- Required properties recap (Fred): https://github.com/dotnet/csharplang/blob/main/proposals/required-members.md
- Improved delegate type arguments (Rikki): https://github.com/dotnet/csharplang/issues/5321
# C# Language Design Notes for 2021
Overview of meetings and agendas for 2021
## Oct 25, 2021
[C# Language Design Notes for October 25th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-10-25.md)
1. Required members
2. Delegate type argument improvements
## Oct 20, 2021
[C# Language Design Notes for October 20th, 2021](https://github.com/dotnet/csharplang/blob/main/meetings/2021/LDM-2021-10-20.md)