# C# Language Design Meeting for July 26th, 2021

## Agenda

1. [Lambda conversion to System.Delegate](#lambda-conversion-to-system-delegate)
2. [Direct invocation of lambdas](#direct-invocation-of-lambdas)
3. [Speakable names for top-level statements](#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:

```cs
(() => {})(); // 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](LDM-2021-07-12.md#speakable-names-for-top-level-statements), 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](https://github.com/dotnet/csharplang/discussions/4928#discussioncomment-1013469) 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.
