Runtime: Add a single parameter, with return type `ValueTuple` overload for `Enumerable.Zip`?

Created on 21 Oct 2017  路  12Comments  路  Source: dotnet/runtime

Instead of writing

foreach (var (x, y) in Seq1.Zip(Seq2, (s1, s2) => (s1, s2)))

we could write:

foreach (var (x, y) in Seq1.Zip(Seq2))

The implementation seems to be trivial:

public static class ZipExtensions
{
    public static IEnumerable<(T, U)> Zip<T, U>(this IEnumerable<T> seq1, IEnumerable<U> seq2)
    {
        return seq1.Zip(seq2, (x, y) => (x, y));
    }
}

Usage

var list = new List<int>{1, 2, 3, 4};
foreach(var (n, i) in list.Zip(Range(0, list.Count)))
{
    Console.WriteLine($"{i}: {n}");
}

Other Languages

Zip-like functions in Rust, C++ (Boost, range-v3) all return tuples.

api-suggestion area-System.Linq

All 12 comments

@AlexGhiondea here's example of API where we would expose ValueTuple from BCL, which would not work well on Framework for light-up scenarios.

This option feels very natural with ValueTuple; this is exactly the sort of syntax benefits that I am expecting from being able to return multiple values.

@karelz I not too sure to understand what would be the problem of exposing ValueTuple in this context. I have looked-up the other issue, but the angle you are pointing out remains unclear to me. Could you shed some light on a scenario where the Zip extension would "backfire" somehow?

@vermorel ValueTuple is loaded twice in apps targeting 4.6 and lower frameworks (from the NuGet package System.ValueTuple), while running on 4.7 (where ValueTuple is also part of mscorlib).
We rely on the fact those are isolated type universes which will never try to interact with each other.
If you light up (dynamically call method exposing ValueTuple as argument on 4.7+) and try to exchange the type with your apps' ValueTuple, you will get runtime errors "Cannot cast ValueTuple to ValueTuple".
The belief is that such scenarios are nearly non-existing. I personally fear that they will bite us one day :( - even if just because the errors "Cannot cast X to X" are weird and hard to understand.

@karelz Thanks a lot for the detailed explanation. The downside is much clearer now.

BTW: I don't view it as downside of this particular API. If ValueTuple is the right type, we should use it. It is more shout out (esp. to @AlexGhiondea @weshaggard @ericstj) that the scenarios which might lead into unfortunate situations are slowly rising and we should be aware of that and incorporate it in our designs of OOBs, policies around them and tooling.

Why not spend some time improving the runtime and tooling so that moving types in-box is more of a first-class experience? What if the CLR could resolve those errors like "Cannot cast X to X" itself, given inboxing annotations?

@jnm2 that is one of many potential solutions with its own list of downsides and complications. Let's take those discussions outside of this API issue please.

Could we have this API in corefx with some #if ValueTupleExist something like that?

@Thaina I don't think so. There isn't anything similar to #if for libraries.

@AlexGhiondea @karelz do you have any concerns for submitting this for review?

I am worried we do not understand the impact of exposing such APIs in BCL. Might be worth having the discussion in API review though. I expect this one will be a tough one.

Was this page helpful?
0 / 5 - 0 ratings