# C# Language Design Meeting for May 10th, 2021

## Agenda

1. [Lambda improvements](#lambda-improvements)

## Quote of the Day

- "I'll allow it"

## Discussion

### Lambda improvements

#### Lambda natural types in unconstrained scenarios

There are a few related open questions around how we handle lambda expressions and method groups in unconstrained scenarios. These
are scenarios such as:

```cs
var a = (int x) => x; // What is the type of A?

void M1<T>(T t);
M1((int x) => x); // What is the type of T?

void M2(object o);
M2((int x) => x); // What is the type of the expression? ie, o.GetType() returns what?
```

These scenarios are all related to how much we want to define a "default" function type in C#, and how much we think doing so could
stifle later development around value delegates (if we even do such a feature). In C# today, we have 3 function types:

* Delegate types that inherit from `System.Delegate`.
* Expression tree types that inherit from `System.Linq.Expressions.**Expression`.
* Function pointer types.

All of these types support conversions from some subset of method groups or lambdas, and none is currently privileged above another.
Overloads between these types are considered ambiguous, and users must explicitly include information that tells the compiler what
type of function type to use, such as by giving a target type. If we allow `var`, conversions to `object`, and/or unconstrained generic
type inference to work, we would be setting in stone what the "default" function type in C# is. This would be particularly noticeable
if our future selves introduced a form of lightweight delegate types and wanted to make them the default in various forms of overload
resolution. We are doing analogous work with interpolated strings currently, but interpolated strings are a much smaller section of
the language than lambda expressions, and lambda irregularities are potentially much more noticeable.

We could protect our future selves here by making the spec more restrictive: Do not allow lambdas/method groups to be converted to
unconstrained contexts. This would mean no `var`, no unconstrained type parameters, and no conversion to `object`. We would only infer
when there was information that we could use to inform the compiler as to which type of function type to use: conversion to just
`System.Delegate` would be fine, for example, because we know that the delegate type version was being chosen. While this would protect
the ability to introduce a value delegate type later and make it the default, we see some potential usability concerns with making
such a delegate type the default. At this point, we believe such a delegate type would be based on ref structs, and making `var`
declare these types would be minefield for async and other existing scenarios. Using such types by default in generic inference would
have similar issues around ref struct safety rules. And finally, if such a type were converted to `object`, it would by necessity need
to be boxed somewhere, obviating the point of using a lightweight value delegate type in the first place. Given these concerns, we
believe that we would just be protecting our ability to make the same decision later, and that another function type would not be a
good "default".

##### Conclusion

We allow inferring a natural type for a lambda or method group in unconstrained scenarios, inferring Action/Func/synthesized delegate
type, as appropriate.

#### Type inference

We went over the rules as specified in the proposal. The only missing bit is that, at final usage, a function type needs to look at
constraints to determine whether it should be inferred to be a Delegate or an Expression.

##### Conclusion

Accepted, with the additional step around constraints.

#### Direct invocation

Finally today, we looked at supporting direct invocation of lambda expressions. This is somewhat related to the
[first topic](#lambda-natural-types-in-unconstrained-scenarios), but could be implemented even if we chose to do the restrictive version
of that issue because this feature would not require us to actually choose a final function type for the lambda expression. We could
just emit it as a method and call it directly, without creating a delegate instance behind the scenes at all. However, we don't have an
important driving scenario behind this feature: technically it could be used as a form of statement expression, but it doesn't feel like
a good solution to that problem. The main thing we want to make sure works is regularity with other inferred contexts:

```cs
// If this works
var zeroF = (int x) => x;
var zero = zeroF(0);

// This should also work
var zero = ((int x) => x)(0);

// But this wouldn't work with var, so is it fine to have not work here?
var zero = (x => x)(0);
```

##### Conclusion

We generally support the idea, even the final example. It may take more work however, and thus may not make C# 10. We'll create a
more formal specification for approval.
