csharplang/meetings/2022/LDM-2022-04-25.md

4.3 KiB

C# Language Design Meeting for Apr 25th, 2022

Agenda

Quote of the Day

  • "The group you're talking about just raised their hand"

Discussion

ref readonly method parameters

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

In another lowlevel session, we looked at a feature designed to address pain points in the BCL with in. For the most part, in works quite well. However, there are a few APIs that have been reluctant to adopt in because of two main reasons:

  • Passing an rvalue, which in allows, is an anti-pattern and should be disallowed for a subset of APIs. This part could be addressed in an analyzer.
  • in requires that in be specified at the callsite for lvalues, not ref. For APIs that would want to move, such as QueryInterface, the source-breaking change of moving to in is undesirable, and blocks adoption of the feature. This is not addressable by an analyzer.

We think that we've left ourselves room in the middle between ref and in for a ref readonly feature, where in can be thought of as ref readonly plus an additional feature of allowing rvalue parameters.

As part of this, we re-examined the motivation behind in allowing rvalues, and behind not allowing ref to be used for in parameters. Rvalues were allowed because the similar feature in Midori originally didn't allow rvalues, and that proved painful for devs in that environment. That environment also had an advantage of being entirely new code: migrating from ref to in or another keyword as a source-break wasn't nearly the pain point it is for the BCL and C#, which has 20-year-old code still in use today.

We therefore believe there is space for two changes to ease the migration path:

  • Allow in and ref to both be used at the callsite for in parameters. in will still be preferred, and a warning will be issued when using ref for such cases, but this will allow a migration path that doesn't completely break consumer code, and the warning can be disabled for codebases that don't want to update.
  • Have a language feature to prevent rvalues being passed where they don't belong. We looked at two possible syntaxes for this: ref readonly, or using an attribute like LvalueOnly, effectively making it an analyzer. After some discussion, we prefer it being ref readonly: it's a language feature, not an analyzer, so it should look like one. We will error when an rvalue is passed to a ref readonly parameter. Both ref and in will be usable at the callsite, but use of ref will warn, like it will for in parameters.

Conclusion

Feature is accepted. The syntax will be ref readonly. ref will be usable for both ref readonly and in parameters at the callsite, but a warning will be issues for such cases. Passing an rvalue to a ref readonly parameter is an error.

Inconsistencies around accessibility checks for interface implementations

https://github.com/dotnet/roslyn/issues/60885

Previously, we relaxed restrictions around non-public interface methods. Unfortunately, this now leaves us with inconsistencies around internal interface methods: implementations of the interface in another assembly end up implementing such internal methods implicitly, even when they lack visibility. This is particularly bad for virtual, non-abstract members, where an interface could be perfectly legal to implement in another assembly, and then adding an internal virtual method could cause that other assembly type to end up overriding an interface member it did not intend to.

In general, we dislike all of the proposed solutions here. Checking to make sure that methods aren't implicitly implementing interface methods doesn't solve the issue when the dependent assembly doesn't recompile. Relaxing the restriction for explicit implementations seems to fly in the face of accessibility in C#. Trying to emulate the exact behavior of class types has a number of holes in it. We think we need to brainstorm more about what to do here.

Conclusion

No action today. We will go back to the drawing board and revisit.