- "When I share on Teams I lose my mouse." "You're a VIM user, you shouldn't be using your mouse anyway."
- "I was expecting this to tear us apart." <2 people post gifs of The Room> "Someone got the reference. He's my totem actor."
Champion Issue: #7700
Issue: dotnet/roslyn#73743
We started today with a shorter discussion on a potential upgrade trap with params
collections in C# 13. Because params Span<T>
is preferred over params T[]
, it will mean
that, on upgrade, call sites start preferring newly-introduced Span<T>
overloads; these overloads cannot be used in expression trees, however, so code that worked fine previously
will now start failing. To work around this, consumers will have to explicitly create an array with new[] { }
, instead of letting params
work as expected. While unfortunate, this
is much the same flavor of breaking change we have encountered in other instances where we introduce new conversions; we think it would be more unfortunate to try and handle this
specially, and then later need to make still more changes if we update expression trees. Given that, we think the best approach is to simply document the potential breaking change
and leave this as is. We'll let this sit over the weekend and think on it, and come back on Monday to make a final decision.
No conclusion today.
Champion Issue: #5497
Related: #8121
Finally, we're back on extension codegen, this time with unfortunate news; our codegen strategy for extensions, and in particular using Unsafe.As
, was rejected by the .NET runtime
architects as fundamentally unsafe. There are potential aliasing issues that could cause parts of the JIT to become confused, particularly in rarer optimization scenarios, and they
cannot guarantee that it will always be safely handled given our intended usage patterns; they would need to teach the runtime to handle these scenarios. Given that one of the goals
of the current emit strategy is that it would need no runtime participation until a later date when we look at interface implementation, this is unfortunate; it would even mean that
we couldn't ship any form of extensions in the .NET 9 timeframe, not even in preview. This is a long-lead feature and will need bake time with real users before we're fully confident
that we have the right design, so we wanted to head back to the drawing board for emit. We see two main approaches:
-
Fully commit to runtime support. If we wanted to go the runtime support route, we wouldn't just rely on
Unsafe.As
; we'd update the runtime to just directly allow ref assignment of an underlying type to an extension type. This would be safer at a runtime level, as it gives it a primitive it can verify. It may also give us a better starting point for later support of interface members. However, we also think that it's unfortunate that we wouldn't be able to get any previewing during the .NET 9 timeframe. While we don't want to be afraid of not shipping features that were promised if they're not ready, this would likely mean that extensions wouldn't be shipped in a stable form until at least .NET 11. This is pretty unpalatable to the LDM. -
Fall back to treating extensions as sugar over static methods on extension types, much like standard extension methods today. There's increased difficulty with the compiler representation here; the public model and internal emit models of these types would have to sugar and desugar to convert between them. It's certainly something that we know how to do today, as we do it with extension methods. That experience tells us that further expanding the sugar is possible, but will have some complicated edges. It will also require more rewrites of member bodies in order to mimic the semantics of instance methods, particularly for nested closures. It is possible, though, and has a couple of advantages:
- A version of this could actually ship in the .NET 9 timeframe, at least in preview. That will let developers get their hands on it to validate our designs.
- Existing extension methods may actually be convertible to the new extension form in a binary-compatible fashion. This could help resolve a concern the LDM has had for a while, that new types would need to be introduced to allow the new style of extension method. It wouldn't be perfect; in particular, any holder of extension methods that has extensions for multiple types likely couldn't work.
We also don't think the runtime work to support extensions implementing interfaces for these types would be prohibitively more expensive than option 1; to the runtime, a static method that takes an object as its first parameter is very similar to an instance method on that object. While it wouldn't be as immediately straightforward as an instance member on an extension type, we also don't think it will be too challenging, especially since we expect to need runtime support for the interface implementation part anyways.
Ultimately, we settled on option 2 here. The binary-compat story is something we want to investigate more with this approach, and the approach still allows for the original goals of the rejected codegen proposal.
We change the codegen strategy for extensions to be based on static methods, much like current extension methods, rather than struct
types and Unsafe.As
.