Skip to content

Latest commit

 

History

History
66 lines (46 loc) · 5.23 KB

LDM-2024-06-24.md

File metadata and controls

66 lines (46 loc) · 5.23 KB

C# Language Design Meeting for June 24th, 2024

Agenda

Quote of the Day

  • Nothing particularly amusing was said today, sorry.

Discussion

First-Class Spans

Champion issue: #7905
Spec link: https://github.com/dotnet/csharplang/blob/dd326f7fb0c282825ed1b2ffbe8180b6c54afa1c/proposals/first-class-span-types.md#conversion-from-type-vs-from-expression

We started today by looking at an open question in the first-class span feature. The question at hand is about a minor difficulty that the compiler team has run into while implementing the feature; by making the conversion a conversion from type, rather from an expression, we've actually run into a novel scenario in the compiler. Currently, all the special-cased types that participate in conversions from the core library itself (ie, the assembly that defines System.Object), not from other assemblies. This fact has led to some of the structure of the compiler around conversions. (ReadOnly)Span, on the other hand, may not come from core library, but may instead come from System.Memory.dll, or the user may define it themselves in source. This means we need to decide how the compiler finds the (ReadOnly)Span type that considered for the conversions defined by this feature. We have a few options for this:

  1. Require that the System.Span and System.ReadOnlySpan considered for the feature come from the core library, like all other types that have special conversion rules.
  2. Restructure the compiler to plumb our existing logic for finding these types into the conversion logic.
  3. Simply match by the full name of the type.

Option 2 is the most consistent with all the rest of the compiler's handling around (ReadOnly)Span, but we're also concerned about the investment cost here. It's potentially a big restructure; not impossible by any means, but it has a fairly low return-on-investment in the long term. Option 1 is the easiest to implement, but we're somewhat concerned about the inconsistencies, particularly with other features that will allow the user to override System.Span with a type defined in source. Finally, option 3 is easier to implement than 2, and likely to be the most consistent with it. It's not perfect; in particular, it will potentially apply to all definitions of System.(ReadOnly)Span, regardless of what assembly they come from, while things like collection expression rules only apply to the canonical definition (regardless of whether that canonical definition comes from source, corelib, or System.Memory.dll). We think that, for 99.9% of users, this will result in identical behavior to 2. Given that, we think option 3 is the best balance here.

Conclusion

We will go with option 3, match System.Span and System.ReadOnlySpan by full name.

field questions

Champion issue: #140
Questions: https://github.com/dotnet/csharplang/blob/dd326f7fb0c282825ed1b2ffbe8180b6c54afa1c/proposals/semi-auto-properties.md#open-ldm-questions

Mixing auto-accessors

The first question up is a simple confirmation question. While the proposal has long included the ability to have one half of a semi-auto property be a set; or get;, we've never explicitly confirmed it in LDM. After a brief discussion, we confirmed that we do indeed want to be able to leave one half of a semi-auto property as an auto accessor.

Conclusion

Confirmed.

Nullability

The next issue took up the rest of our time today, without reaching a final conclusion. Nullability of the backing field here is very tricky: we do almost no inter-procedural analysis of methods today (except for local functions), and it very much seems like we will need to do this type of analysis to get the nullability correct. There's also a lot of edge cases to consider, particularly around lazy initialization. One thing that became very clear was that the proposed [field: NotNull] approach wasn't an acceptable tradeoff to the LDM. Nullability does make a lot of pragmatic cuts where it is possible to observe null values, such as arrays. However, we think that this isn't a place where we could accept that type of tradeoff; arrays are a local and obvious source of nulls. Lazy initialization through multiple constructors or methods is hard to get right and much subtler to debug. We are somewhat concerned about having a magic solution though, especially given our experience with var. While there are no safety holes introduced from our treatment of var as allowing null assignments, we do know that a non-zero percentage of our users are confused by the behavior; even if it's completely safe, there's a perception that the guardrail is too loose, and it causes these users to lose their trust of the feature. If we did fancy cross-method analysis for field, and allowed null assignments to the backing field even when it's provably perfectly safe, is that ok? Or will that confuse users and cause them to distrust the feature? We want to kick these questions back to a small group to noodle on, so we will leave these for now and revisit in the near future.