In Javascript ES6, you are able to destructure arrays like this:
const [a,b,...rest] = someArray;
where a is the first element
You need to be slightly careful if you want to handle infinite streams, as from a while(true) yield return block for example. In that case, you can't practically check the length of the stream to make sure you have enough items to populate the requested tuple.
If your source is actually infinite a combination of the above approaches would work -- rather than counting the length of the IEnumerable, just check that it has any content at all, and then implement the multi-parameter overloads in terms of the single-parameter overload:
public static void Deconstruct(this IEnumerable list, out T head, out IEnumerable tail)
{
head = list.First(); // throws InvalidOperationException for empty list
tail = list.Skip(1);
}
public static void Deconstruct(this IEnumerable list, out T head, out T next, out IEnumerable tail)
{
head = list.First();
(next, tail) = list.Skip(1);
}
The critical question is what you want to happen when the stream runs out. The code above will throw an InvalidOperationException. Returning default might not be what you want instead. In a functional context you'd typically be doing a cons, and splitting the stream into a single head an stream tail - and then checking for empty streams outside of your cons implementation (so outside of the Deconstruct method).