Roslyn: Allow Deconstruct and implicit operator to both support deconstruction and conversion to tuple types

Created on 6 Jan 2017  路  6Comments  路  Source: dotnet/roslyn

With reference to the discussion on #16199, whilst tuples and deconstructions are different things, the need to define two ways of converting from a type to a deconstruction or a tuple respectively, seems an unnecessary overhead.

Take the following code by way of example,

````cs
public class PseudoTuple
{
public PseudoTuple(T1 item1, T2 item2)
{
Item1 = item1;
Item2 = item2;
}

public T1 Item1 { get; }
public T2 Item2 { get; }

public void Deconstruct(out T1 item1, out T2 item2)
{
    item1 = Item1;
    item2 = Item2;
}

}

...

void F((int, string) tuple) { }
var t = new PseudoTuple(1, "a");
var (x, y) = t; // Deconstruction. Works fine.
F(t); // This line doesn't compile as can't convert PseudoTuple to ValueTuple
F((x, y)); // Creating a tuple from x, y and passing that. Works fine.
Add the following to `PseudoTuple` and all then compiles: cs
public static implicit operator (T1, T2)(PseudoTuple tuple) =>
(tuple.Item1, tuple.Item2);
It would be useful if both `Deconstruct` and `implicit operator` could be used for both purposes, requiring only one to be defined. So having `public void Deconstruct(out T1 item1, out T2 item2)` **or** `public static implicit operator (T1, T2)(PseudoTuple<T1, T2> tuple)` defined in `PseudoTuple` then the following statements would compile fine: cs
void F((int, string) tuple) { }
var t = new PseudoTuple(1, "a");
var (x, y) = t;
F(t);
F((x, y));
````

This would have the added advantage that a Deconstruct extension method could be used to allow implicit conversions to tuples for 3rd party types, as extension operators aren't (yet) supported.

Area-Language Design Feature Request New Language Feature - Tuples

Most helpful comment

@DavidArno No, it would not be a "trivial fix". Deconstruction can be added by extension methods, and conversions cannot. There are good reasons for both.

All 6 comments

Just to clarify, this would go both ways, right?

public class Foo {
    public int X { get; } = 123;
    public int Y { get; } = 456;

    public void Deconstruct(out int x, out int y) {
        x = X;
        y = Y;
    }
}

public class Bar {
    public int X { get; } = 123;
    public int Y { get; } = 456;

    public static implicit operator (int x, int y)(Bar bar) {
        return (bar.X, bar.Y);
    }
}

// silent conversion to a tuple
var foo = new Foo();
(int x, int y) tuple = foo;

// translated as
var foo = new Foo();
(int x, int y) tuple;
foo.Deconstruct(out tuple.x, out tuple.y);

// silent deconstruction
var bar = new Bar();
var (x, y) = bar;

// translated as
var bar = new Bar();
var (x, y) = (ValueTuple<int,int>)bar;

@HaloFour,

Thanks for that clarification. That is exactly what I was trying to say.

We are not contemplating any further feature work in C# 7. This proposal would be a breaking change from C# 7 (the addition of a conversion may make an otherwise inapplicable method applicable, and better than the candidate selected in a previous version of the language). We are therefore unlikely to do this.

@gafter,

That's unfortunate. Having caught myself out with this just 24 hours after commenting on #16199, I now realise that @mharthoorn is right and that the deconstruction/tuple dichotomy will cause lots of confusion to developers. This suggestion would have been a trivial fix to that confusion.

Oh well, I guess this is another one to add to the long list of things that will have to be fixed via generators, if/when we get them.

@DavidArno No, it would not be a "trivial fix". Deconstruction can be added by extension methods, and conversions cannot. There are good reasons for both.

@gafter

How about

Tuple<string, int> foo = ("", 0);

And vice versa?

Was this page helpful?
0 / 5 - 0 ratings