Since order is explicitly undefined between enumeration of a collection expression spread element and evaluation of the next collection expression element, folks will sometimes need to force enumeration early. Forcing enumeration early is easy, familiar, and reads nicely:
// Goal: enumerate the iterator method ReadHeaderLines completely,
// and call ReadBody only afterward.
[.. ReadHeaderLines().ToList(), ReadBody()]
The only downside is that this allocates an intermediate List<T> or T[]. However, this intermediate allocation is immediately spread, so the compiler could elide the allocation at its discretion without language users being able to tell the difference. This is in line with tentative plans to do similar eliding of collection instances in foreach (var x in new[] { a, b, c }) and stack-allocating instead.
The important part would be that the semantics are preserved: enumeration of ReadHeaderLines() must finish before the evaluation of ReadHeaderLines().ToList() completes. Even with the ToList call being elided as a compiler optimization, the call is still there in concept, and is still causing enumeration to happen as part of evaluating the spread expression.
Only Enumerable.ToList/ToArray should be elided. Instance ToArray methods such as ConcurrentDictionary.ToArray can't be elided without changing the semantics. (ConcurrentDictionary.ToArray creates an atomic snapshot, and enumerating ConcurrentDictionary does not.)
Since order is explicitly undefined between enumeration of a collection expression spread element and evaluation of the next collection expression element, folks will sometimes need to force enumeration early. Forcing enumeration early is easy, familiar, and reads nicely:
The only downside is that this allocates an intermediate
List<T>
orT[]
. However, this intermediate allocation is immediately spread, so the compiler could elide the allocation at its discretion without language users being able to tell the difference. This is in line with tentative plans to do similar eliding of collection instances inforeach (var x in new[] { a, b, c })
and stack-allocating instead.The important part would be that the semantics are preserved: enumeration of
ReadHeaderLines()
must finish before the evaluation ofReadHeaderLines().ToList()
completes. Even with the ToList call being elided as a compiler optimization, the call is still there in concept, and is still causing enumeration to happen as part of evaluating the spread expression.Only Enumerable.ToList/ToArray should be elided. Instance ToArray methods such as ConcurrentDictionary.ToArray can't be elided without changing the semantics. (ConcurrentDictionary.ToArray creates an atomic snapshot, and enumerating ConcurrentDictionary does not.)