views:

100

answers:

2

In a Tuple, if you have more than 7 items, you can provide an 8th item that is another tuple and define up to 7 items, and then another tuple as the 8th and on and on down the line. However, there is no constraint on the 8th item at compile time. For example, this is legal code for the compiler:

var tuple = new Tuple<int, int, int, int, int, int, int, double>
                (1, 1, 1, 1, 1, 1, 1, 1d);

Even though the intellisense documentation says that TRest must be a Tuple. You do not get any error when writing or building the code, it does not manifest until runtime in the form of an ArgumentException.

You can roughly implement a Tuple in a few minutes, complete with a Tuple-constrained 8th item. I just wonder why it was left off the current implementation? Is it possibly a forward-compatibility issue where they could add more elements with a hypothetical C# 5?

Short version of rough implementation

interface IMyTuple { }

class MyTuple<T1> : IMyTuple
{
    public T1 Item1 { get; private set; }
    public MyTuple(T1 item1) { Item1 = item1; }
}

class MyTuple<T1, T2> : MyTuple<T1>
{
    public T2 Item2 { get; private set; }
    public MyTuple(T1 item1, T2 item2) : base(item1) { Item2 = item2; }
}

class MyTuple<T1, T2, TRest> : MyTuple<T1, T2> where TRest : IMyTuple
{
    public TRest Rest { get; private set; }
    public MyTuple(T1 item1, T2 item2, TRest rest)
        : base(item1, item2)
    {
        Rest = rest;
    }
}

...

var mytuple = new MyTuple<int, int, MyTuple<int>>
                 (1, 1, new MyTuple<int>(1)); // legal
var mytuple2 = new MyTuple<int, int, int>(1, 2, 3); // illegal at compile time
+1  A: 

The hypothetical ITuple constraint wouldn't really constrain it to be a tuple [1], would it? Just a class that implements ITuple.

[1] - I'm defining "tuple" to be one of the BCL-provided Tuple<> classes.

Stephen Cleary
That's an interesting point. You're right, any old type could implement the interface (whatever that entails) and fulfill the constraint's requirement. But then I guess it also begs the question of why restrict the type at runtime, you can drop a Tuple into any one of the existing slots, just say "we're making an 8-slotted (max) generic class, use it as you see fit."
Anthony Pegram
That's the only way to truly constrain it to be a tuple (runtime check for an `internal` interface, so we can't implement it). The last slot actually does have to be a tuple because it affects the implementation of `Size`, `GetHashCode`, `ToString`, etc. It's treated totally differently than the other slots.
Stephen Cleary
+1  A: 

It's a limiation of the type system. ITuple is an internal interface. If it was a generic constraint, it would need to be public, which would then let everyone implement their own ITuple which could not have anything to do with tuples. Restricting it to internal lets the BCL team guarentee that it is actually some sort of tuple, but results in TRest being a bit less compile-time safe than it could be.

thecoop