Skip to content

Latest commit

 

History

History
60 lines (41 loc) · 4.55 KB

LDM-2023-09-25.md

File metadata and controls

60 lines (41 loc) · 4.55 KB

C# Language Design Meeting for September 25th, 2023

Agenda

Quote(s) of the Day

  • "So we're finally going to have the highlander betterness rule?"
  • "Let them live in fear if they're going to do something like this"

Discussion

Primary constructors

#2691
https://github.com/dotnet/csharplang/blob/960ffda90c05c212870d509a45651197a6cd1791/proposals/csharp-12.0/primary-constructors.md#lookup-order-for-type-parameters

First up today we looked at an issue with lookup order of type parameters, and how our existing records work conflicts with the rules we decided on for non-record primary constructors. We have 4 options for addressing this discrepancy:

  1. Adjust the rules to match the behavior of the implementation (which is the same between record and non-record types).
  2. Adjust the behavior to match the rules in all cases (a possible breaking change for records).
  3. Disallow a primary constructor parameter to use a type parameter's name (a possible breaking change for records).
  4. Do nothing, accept the inconsistency between the spec and implementation.

We quickly determined that we don't think 2 or 4 are the correct answers, and instead felt divided between 1 and 3. Importantly, the LDM feels that this scenario is a pathological case, and not representative of C# code outside the compiler's test suite, so we don't feel the cost of a breaking change is hard. However, because this case is so pathological, we also are unsure whether it's worth spending the effort that taking a breaking change would require: updating the compiler error detection code, documenting the breaking change, and dealing any fallout from the change, and all this within the next month when C# 12 releases. We ultimately think that the best choice we can make here is to simply update the spec to match the behavior of the compiler, and revisit in the future if we have sufficient motivation from real world scenarios.

Conclusion

Option 1, update the primary constructors spec to match the existing compiler behavior and align with records.

Defining well-defined behavior for collection expression types

#5354
#7542

For our second and last issue today, we looked at defining what behavior the compiler can assume from a collection type. This is important for allowing the compiler room to change emit of collection expressions for performance, and there's a tension here between what could be reasonably observed by a user program vs what should be able t reordered. One thing we think is iron-clad is that anything the user has explicitly written needs to be evaluated in traditional C# fashion. It is reasonable that [i++, i++, i++] would result in a collection of [0, 1, 2] with i == 3 afterwards, and not any other order. However, enumeration of nested collections is not an explicit user action, and we want to able to control the location that occurs in; enumeration should be able to occur before evaluating subsequent elements, or after evaluating subsequent elements, as needed by the compiler to support efficient intermediate storage allocation.

We like the spirit of the proposed rules in 7542 but think that they need to explicitly spell out these conditions. Right now, they imply that the compiler can reorder the location that nested enumeration can occur, but don't explicitly state it. Rather than leaving this as undefined and letting the compiler fill in the blanks, we'd rather explicitly carve it out that the compiler is free to optimize assuming that IEnumerable instances can be enumerated at any time, so long as the element expressions that the user writes are evaluated in left-to-right order. We also don't feel that we should specify that the compile needs to enumerate spreads in the order they appear; while we currently don't have any plans for enumerating a later spread before an earlier spread, we don't think that we should restrict ourselves from optimizations in the space in the future if we find them. We support spreading IEnumerables, not IEnumerators, and those should be iterable multiple times without producing different results each time.

Conclusion

The compiler is allowed to reorder spread enumerations assuming that IEnumerable implementations don't have side effects, and the rules should be updated to explicitly call this out.