meetings/2019/LDM-2019-01-16.md
await foreachQ: Allow shadowing for all lambdas as well?
A: Yes.
Q: Allow shadowing with range variables in LINQ queries?
// char c;
var q = from c in s
from c2 in s
where c != ' '
select c;
var q2 = s
.SelectMany(c => s, (c, c2) => new { c, c2 })
.Where(_x => _x.c != ' ')
.Select(_x => _x.c);
c and c2 can't be named the same because they are equivalent to two
parameters being named the same. However, should the new c be able to
shadow the local c?
A: Let's look at the implementation and decide based on the complexity.
await foreachWithCancellation and ConfigureAwait both return a custom type that does
not implement the interface, just the pattern. await foreach does not pick
it up because it does not have pattern-based disposal and the type cannot
implement the IAsyncDisposable type because it does not produce a ValueTask
return for disposal.
Proposals:
Just allow pattern-based disposal for IAsyncDisposable. Only allow
pattern-based disposable for IDisposable in ref structs.
a. For await foreach, use the pattern, then dynamically check for
interface and use it if present.
b. For await foreach, use the pattern, then statically check for the
interface and use it if present.
The dynamic check in (1a) is used because in C# 1.0 the non-generic IEnumerator
did not implement IDisposable.
The next question is whether to consider extension methods. The standard pattern we've previously settled on is:
Can we use this pattern for IAsyncDisposable? The primary question is whether
to consider extension methods.
Conclusion
Let's do 1b. We do not have a non-generic IAsyncEnumerator that doesn't
implement IAsyncDisposable, so the dynamic check is unnecessary.
We will not consider extension methods for IAsyncDisposable or
IDisposable (on ref structs). We will consider extension methods for
IAsyncEnumerable and IEnumerable.