csharplang/meetings/2022/LDM-2022-03-23.md

4.1 KiB

C# Language Design Meeting for March 23rd, 2022

Agenda

  1. Open questions in required members
    1. Emitting SetsRequiredMembers for record copy constructors
    2. Should SetsRequiredMembers suppress errors?
    3. Unsettable members
    4. Ref returning properties
    5. Obsolete members

Quote of the Day

  • "We can and do allow users to shoot their feet off. However, lets not give them something capable of doing nothing else"

Discussion

Open questions in required members

https://github.com/dotnet/csharplang/issues/3630
https://github.com/dotnet/csharplang/issues/5945

Emitting SetsRequiredMembers for record copy constructors

We're not ok with option 1 here: these constructors can be accessed directly by consumers within the record type or any derived type of the record. We also think that option 2 changes too much metadata to be palatable: every existing record would change on recompile. While incorrect compilation order could result in a SetsRequiredMembers being missed from a derived record, we think that this case is sufficiently in the corner that it's not necessary to try and address.

Conclusion

Option 3, SetsRequiredMembers will be added to record copy constructors when the record or any base type has required members.

Should SetsRequiredMembers suppress errors?

This is a corner case, as the scenario cannot arise from C# code, but it could potentially occur if another language were to extend a type with required members and either override (without applying the correct attributes) or hide those members. This would cause the required member list to not be understood by the language, and there is danger in allowing something we don't understand to proceed. However, in those cases, the external language user did decide to explicitly add the SetsRequiredMembers attribute: this is a signal we can understand without context, so it seems fine to ignore errors around required members if the attribute is found.

Conclusion

SetsRequiredMembers will suppress the error.

Unsettable members

We've previously said constructors that require members must be at least as accessible as the members, to ensure that constructors don't become uncallable. This is just an extension of that scenario.

Conclusion

We will require that required fields cannot be readonly, and that required properties are settable from every constructor (meaning that they have a setter/initer at least as accessible as every constructor that requires them to be set).

Ref returning properties

There's an interesting debate here similar to the placement of readonly in comparison to the ref: does required here require setting of the ref itself (not possible with ref properties, might be possible with ref field?), or does it require setting the value pointed at by the ref? If the former, that would suggest required ref to be in line with readonly members, and would necessitate a syntax for initializing a ref in an object initializer, which doesn't exist today. If the latter, it would suggest ref required, to be in line with ref readonly, but it's unclear if this is a scenario to be concerned with.

Conclusion

Given lack of motivation, this is disallowed entirely (on both ref properties and, when added, ref fields). We can revisit in the future if we have motivating use cases.

Obsolete members

Finally, we considered Obsolete required members. We're not fans of libraries forcing their users into a warning, either by accident (adding Obsolete to a member while forgetting to remove required) or intentionally. However, we don't feel this is worth an error: it's technically understandable, we just don't know why someone would intentionally do it. This category of issue is best served by warnings, so we think that's the appropriate strategy.

Conclusion

Option 3, with a warning. Warnings will be suppressed for Obsolete constructors and for types that are obsolete.