LinqAF: SelectMany and boxing
Posted: 2018/01/23 Filed under: code Comments Off on LinqAF: SelectMany and boxingThis is part of a series on LinqAF, you should start with the first post.
What’s weird about SelectMany?

Selecting many cats.
Unlike most other LINQ operators, SelectMany is used with a delegate that returns another enumerable. Because a delegate is involved arbitrary logic may be invoked, which means that the “type” of enumerable returned may not be constant.
For example, the following code is perfectly legal:
new [] { 0, 1 }.SelectMany( i => i % 2 == 0 ? new [] { "foo" } : System.Linq.Enumerable.Empty<string>() )
This presents no problem for LINQ-to-Objects since both enumerables implement IEnumerable<T> and there’s a free (in that it doesn’t allocate) upcast, but for LinqAF no such thing exists.
There’s no allocation-free way to handle this case, we must “box” the enumerable returned in either path. For this purpose I introduced a BoxedEnumerable<T> which every enumerable can be converted to with a Box() call (an explicit cast also exists for all LinqAF’s enumerables). This does result in an allocation (the boxed enumerable must be placed on the heap).
This does require changing the above example to:
new [] { 0, 1 }.SelectMany( i => i % 2 == 0 ? new [] { "foo" }.Box() : LinqAF.Enumerable.Empty<string>().Box() )
This represents the only intentional non-“type inference compatible” deviation from LINQ-to-Objects. While SelectMany is the operator this deviation is most likely to occur with, any case where different operators are coalesced into a single expression can trigger it.
I consider the BoxedEnumerable<T> type a blemish on LinqAF but I was unable to come up with a workable alternative, so if you come up with one I’d be interested in hearing about it.
What’s next?
I’ll be going over how LinqAF is tested.