- "If the runtime team jumped off a bridge, would you [redacted]?" "If it would make my code faster"
- "Quote of the day may need to involve corn fields"
Today we looked over the changes around supporting IEnumerable
types in list patterns, and how slice patterns will affect them. While
we overall like the lowering that has been proposed, we would like to continue to look at possible optimizations around using framework
apis such as TryGetNonEnumeratedCount
. This will allow the framework to do all the grungy bookkeeping to make this quick for cases when
the IEnumerable
is actually a countable type, or one of a certain type of LINQ expression that is countable under the hood (such as a
Select
over an array). The runtime is also planning on adding a Take
method that does similar bookkeeping with index and range, falling
back to buffering if it has to.
We also considered to what extent we should allow sub-patterns under a slice pattern. The obvious use case is a declaration pattern for the slice, but as worded today the syntax will allow any arbitrary sub-pattern on the slice. After discussion, while we think that the main use case is just declaration patterns, we see no reason to disallow other nested sub-patterns. It should compose well, and while 99% of users will never need it, it could be helpful for that 1%.
The other question with slice patterns is whether to allow nested sub-patterns for IEnumerable
as well as for sliceable types. If we do
allow this, it would mean treating IEnumerable
specially here, while indexers and slicers cannot be used in the general case. Given
this, we think it will be a better experience if we only allow sub-patterns under a slice if the type is actually sliceable. Separately, we
can look at considering extension methods as a part of general sliceability, which, if combined with renaming that Take
method from the
framework to Slice
before it ships, would enable the feature in a much more general fashion.
- Lowering is generally approved.
- Slice sub-patterns will allow any pattern, so long as the input type to the list pattern is sliceable.
- Making
IEnumerable
sliceable is orthogonal.
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md
After some implementation work, this proposal is back to look at some more changes. One of the big ones is moving the return type to the left
side of the parameter list. This makes the syntax analogous to our other signature declarations in C#, looking like an unnamed version of a
local function. This fits in well with the types of changes we've been making to C# in recent versions, such as tuples/record structs, anonymous
classes/record classes, and declaration forms/pattern forms. While we do have Func
and delegate*
as types that put the return last, we are
at least consistent within type forms and within signature declaration forms. At this point, the only parity we are missing between lambdas
and local functions is the ability to declare generic type parameters, but those won't be useful on lambda expressions unless we add
higher-kinded types to the language.
We also looked at requirements around return type specification: do we want to require that, if a return type is specified, parameter types must be specified too? On the one hand, we require that, if any parameter types are specified, the others must be specified as well. On the other, we can't make it required to specify the return type when a parameter type is specified because C# hasn't had such an ability until now, so requiring this would lack symmetry. It's also very possible that the return type of a lambda could be uninferrable, while the parameter types are, and it would be unfortunate if you had to specify everything in order to just get the return type. Given this, we will allow the return type to be specified without parameter types.
We considered the case of async async (async async) => async
. We could make it required to escape async
used as a type name here: if the user
wants to specify the return type of the lambda is the type named async
and the lambda is not an async lambda, they'll have to escape it anyway
to disambiguate between making the lambda async
. Given this, we support making it required to escape the type name in the return type.
The changes around attributes in the proposal raised no concerns. These changes were requiring that, if an attribute is used, parentheses must be used for the parameter list, and the rules around how the compiler will disambiguate conditional array accesses and dictionary initializers.
Finally, we noted the possibility for a breaking change if single-method method groups are given a natural type with the following code:
using System;
var c = new C();
D.M(c.MyMethod);
// Outputs "Extension" today, would print Instance if c.MyMethod had a natural type.
class C
{
public void MyMethod() { Console.WriteLine("Instance"); }
}
static class CExt
{
public static void MyMethod(this C c, string s) { Console.WriteLine("Extension"); }
}
class D
{
public static void M(Delegate d) { d.DynamicInvoke(); }
public static void M(Action<string> a) { a(""); }
}
We'll need to investigate to see if we can avoid this change, or if we're ok with the potential break.
- Return type before the parameter list is approved, does not require parameter types to be specified.
async
as a return type name should require escapes.- Attribute changes are approved.