Back to Csharplang

C# Language Design Meeting for December 15th, 2021

meetings/2021/LDM-2021-12-15.md

latest3.9 KB
Original Source

C# Language Design Meeting for December 15th, 2021

Agenda

  1. Required parsing
  2. Warnings for parameterless struct constructor

Quote of the Day

  • "Please don't make that the quote of the day. We want to project responsibility to the community."

Discussion

Required parsing

https://github.com/dotnet/csharplang/issues/5439

The main question here is whether we should allow types named required in the language in C# 11, without escaping the name with an @. We did a similar thing for record in C# 9, but in that scenario record had true syntactic ambiguities. For required, there aren't true syntactic ambiguities: just like with async, it is possible to fully disambiguate types named required and required used as a modifier with enough lookahead. However, we have started taking a harder stance against types named with all lowercase 'a'-'z' characters: in .NET 7, we will be report a warning on such type names in general. While we still want to make sure that we're choosing names for new keywords that are unlikely to conflict with user-defined types, we think required is unlikely to be a type name, even beyond the general C# convention of not naming in lowercase, as required is not a noun. Even for record, which is a noun and reasonable one to use (for a record in a DB, as an example), we heard little to no complaints about erroring on it. Therefore, we are comfortable making required illegal as a type name without using an @ to escape it.

Conclusion

required will be disallowed as a type name in C# 11. In general, we are ok with taking over all-lowercase identifiers that can be confused for type names, so long as we do our due diligence in making sure that we're not breaking existing common usages.

Warnings for parameterless struct constructor

https://github.com/dotnet/csharplang/issues/5546

This issue around new S() where S is a struct without a parameterless constructor is a particularly thorny area. There are three main paths we could take to resolve it, each with significant downsides:

  1. Warn on field initializers when a parameterless constructor will not be created. This is painful for users trying to share initializer logic across multiple other constructors, and is also painful for record structs. If a user wants to change anything about a record struct parameter (ie, turn the property into a field, make one property init-only, add a validation check) there is no alternative but making a field initializer.
  2. Warn when calling new S() if S doesn't have a parameterless constructor. This is an extremely broad hammer, as this code has been legal since C# 1. It also has bad interactions with generics, as where T : struct implies where T : new(). We think this option is like attempting to use a sledgehammer to drive in a finishing nail.
  3. A more limited version of 2 where we only warn if the struct in question has field initializers. This heuristic breaks almost immediately, as we have no way to determing whether a struct from metadata has field initializers.

This might be a place that an analyzer implementing option 1 would make more sense than a compiler warning: analyzers can be more configurable than analyzer warnings, both in their severity levels, and in accepting additional options to tune the analyzer. An analyzer will also be able to do more heuristics than we feel comfortable doing in the language, such as detecting when initializers are only using the primary constructor parameters in record structs.

We also looked at the second issue listed in the bug, but determined that it is already an error, and we did not need to make any further changes.

Conclusion

We'll look at doing an analyzer implementing a warning on structs with field initializers that do not generate a parameterless constructor, with some amount of heuristic suppression for scenarios where it is unavoidable.