csharplang/meetings/2021/LDM-2021-07-26.md
2021-07-27 12:34:38 -07:00

6.3 KiB

C# Language Design Meeting for July 26th, 2021

Agenda

  1. Lambda conversion to System.Delegate
  2. Direct invocation of lambdas
  3. Speakable names for top-level statements

Quote of the Day

  • "You just don't want me to have poor man expression blocks"

Discussion

Lambda conversion to System.Delegate

https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md

We've received a few bug reports from customers on upgrading to a new version of the preview SDK that existing code, targeting .NET 5, was now failing to compile because code that previously chose an extension method with a strongly-typed delegate type was now binding to an instance method that took a Delegate instead. While this is a break we intended to make, we wanted to revisit it and make sure that we still believed it was appropriate for these cases. While we are still waiting to hear back from these customers as to what their extension method was actually doing, a survey of code on GitHub shows that the vast majority of these are what we expected: the extension forwards from a strongly-typed delegate to the Delegate instance method. Given this, we believe that our original decisions around this feature are still what we were expecting, and that we will keep the behavior for C# 10.

However, we are also concerned with not making tooling updates that break our users (beyond bugfixes, such as the ternary type inference issues in C# 9's initial release). This is code that has been compiling successfully for a decade or more, and we don't want to break it when the user has only updated their version of VS, and not actually updated to a new version of .NET (ie, using VS 2022, but still targeting .NET 5 or lower). In order to preserve this, we will bring back our workaround for the 16.10 release, where we changed the binding of this case depending on the current language version. It does mean that there will be a subpar tooling experience for upgrades involving this type of code, but we think missing codefixes are better than code that completely stops compiling.

Conclusion

We will keep the current behavior for C# 10. C# 9 and lower will have a different binding behavior, compiling as they used to.

Direct invocation of lambdas

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

Currently, the lambda improvements proposal states that lambdas should be directly invocable. While we think this could fall out for some scenarios, it will not do so for all scenarios. For example:

(() => {})(); // Infer Action, can be invoked
(x => x)(1); // Cannot infer a delegate type on its own: would need to take the argument expression into account

We don't have a strong scenario for this feature at the moment: our best justification for the feature would be as a poor replacement for expression blocks, and we've received vocal and vociferous feedback from the community on the "poor" part of that phrase. We do think it will be odd that lambdas will be able to be assigned to var and then be invoked/used as instance receivers, but cannot be invoked/used as instance receivers directly, but we believe that if we explicitly block this scenario now, we will adequately preserve our design space to remove this restriction later, if we have a better scenario we want to enable.

Conclusion

Lambda and method group natural types will only be allowed to surface in specific contexts: var, method type inference, determining the best type of a group of types, and conversion to System.Delegate/System.Linq.Expressions.Expression. No direct invocation of lambdas or instance member access on lambda expressions or method groups will be allowed.

Speakable names for top-level statements

Two weeks ago, we made a decision that top-level statements would be sugar for a partial Program type in a Main method. However, a comment on the subsequent discussion gave us a separate idea that we had not considered in the meeting, and we wanted to bring up the idea: naming the type that contains the top-level statements after the name of the file the statements are in. There are a few wrinkles to this: what if the file name contains characters that are not legal as C# identifiers? Or what if there is no file name, and the text was passed directly to the compiler not in a file (as is possible using the Roslyn APIs)? We're also concerned by the fragility of this solution: renaming a file could potentially leave dangling partial types and no longer have methods in scope for the top-level statements. Additionally, C# today does not depend on file layout or structure for programs: file names do not have to line up with type names, and namespaces are entirely unconnected from the physical layout of files. This proposal would change that, and we're not sure for the better.

However, the idea that we might have a future where we want to combine multiple files, each with top-level statements, into a single program is a distinct possibility. As we move towards the idea of dotnet run Program.cs, it's conceivable that a single program might have a few files for different UI stacks (for example, WebUI.cs, ConsoleUI.cs, and Desktop.cs), each of which shares a bunch of common files in the same directory. Users would then choose which to run by just saying dotnet run Console.cs, and all 3 of these UI entrypoint files would be combined into a single program, with the entrypoint selected by the file that was run. Given that our specific ask for the speakability feature is being able to get access to the current Assembly (via typeof(Program).Assembly), we think that we can protect future design space here by only making Program speakable, rather than both Program and Main. This will allow our future selves a space to design this multi-file experience without worrying about having multiple methods named Main in the same type, as we will be able to combine these different partial Program types into a single one and name the entrypoints whatever we need to.

Conclusion

We will keep the type name Program and make it speakable, but we will not make the Main method speakable.