# C# Language Design Meeting for March 23rd, 2020 ## Agenda 1. Triage 2. Builder-based records ## Discussion ### Triage #### Generic constraint `where T : ref struct` Proposal: #1148 This is a very complicated area. It's probably not good enough to add this generic constraint, because things like default interface methods create a boxed `this` parameter. It's likely that we would need runtime support to make this safe. This is somwewhat related to the designs in the shapes/roles proposal in that it's about using the "shape" of an interface, possibly with more restrictions than interfaces themselves. Since both proposals may require runtime changes it would be valuable to batch up those changes together. ##### Conclusion Push to at least C# 10.0. Should be considered in concert with the shapes/roles proposals. #### Improve overload resolution for delegate compatibility Proposal: #3277 This is a parallel to changes we previously made to betterness where we remove overloads that will later be considered invalid, to be removed from the overload resolution candidate list in the beginning. This functionally will cause more overload resolution calls to succeed, since invalid candidates will be removed and this will prevent overload resolution ambiguitiy. ##### Conclusion Tentatively added to C# 9.0. We'd like this proposal for function pointers, so if we were to implement this for function pointers and correct overload resolution for delegates at the same time, that would be desirable. #### Allow GetEnumerator from extension methods Proposal: #600 First thing is to confirm that there's no compat concern. When we tried to extend the behavior for `IDisposable` we ran into a problem because `foreach` *conditionally* disposes things which match the `IDisposable` pattern. This means that if anything starts satisfying the pattern which didn't before, an existing method may be newly called. If we ever conditionally use the `foreach` pattern this would probably also be a breaking change. ##### Conclusion Willing to accept it any time, as long as we confirm that it's not a breaking change. ### Builder-based records When discussing records we've had various designs that focus on "nominal" scenarios, where the members of the record are set by name, instead of lowering into method parameters. One proposed implementation strategy is a new series of rules around initialization that we've sometimes called "initonly." We've also looked at using struct "builders" in the past for a similar purpose, and would like to revisit some of these discussions. We have a proposal from a community member, @HaloFour, that lays out another example implementation strategy that we're using for discussion. https://gist.github.com/HaloFour/bccd57c5e4f3261862e04404ce45909e There are certainly some advantages to this structure: * Uses existing valid C# to implement the pattern, making it compatible with existing compilers. If we avoid usage of features like `ref struct` and `in`, it could be compatible for even older consumers, since this would be binary compatible with C# 2.0 metadata. * Allows the type being built to always see the whole set of property values being initialized, meaning that the author of the type can validate the new state of the object. * No new runtime support for any features (e.g., does not require covariant returns) There are also some disadvantages. Performance could be a problem. For classes, the biggest concern is stack size. Currently, initializing a class with an object initializer only requires a single pointer on the class and then each member is initialized separately, the initializer values don't all need to be on the stack simultaneously. If we use a struct builder, the entire builder needs to be on the stack before initialization. For structs, there is the extra stack space cost, but having a builder also effectively doubles the metadata size of the every struct. It's also potentially harder for the CLR to optimize the initialization and remove dead stores through the double-struct passing. If we go forward with this approach we should consult the JIT for their perspective. We're also not sure that this approach fully eliminates all brittleness in adding/changing fields and properties across inheritance, especially if the inheritance is split across assemblies and only one author is recompiled, or they are recompiled in a different order. If we can find a way to close those holes, or limit the feature to prevent these situations, that could be an important mitigating factor. #### Conclusion There's a difficult balance here. Some members are focused on about performance, some prioritize ecosystem compat, and others prioritize "cleanliness" of design, in different directions. Almost everyone has a different priority and prefers different approaches for different reasons. We need to discuss things more and reduce some of the unknowns.