csharplang/meetings/2019/LDM-2019-01-16.md
2019-01-28 01:27:48 -08:00

2.2 KiB

C# Language Design Notes for Jan. 16th, 2019

Agenda

  1. Shadowing in lambdas
  2. pattern-based disposal in await foreach

Discussion

Shadowing in nested functions

Q: 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.

Pattern-based disposal in await foreach

WithCancellation 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:

  1. 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:

  1. Check for pattern
  2. Check for interface
  3. Check for extension methods

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.