meetings/2021/LDM-2021-10-25.md
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. 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:
init(Prop) to signal that the constructor requires all things the type does, except the members in the init clause.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.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:
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:
req, that is used for a required property instead of init?
default(StructType). Some thought needs to be put into that.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.
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:
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?
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.