c#


C#7 value tuple/deconstruction asymmetry


Fiddle here.
Given a function (string a, string b) F(), you can deconstruct the tuple it returns:
var (a, b) = F();
(string c, string d) = F();
Or you can just assign it:
var (a, b) e = F();
(string a, string b) f = F();
var g = F(); // One of these things is not like the others.
Class deconstructors behave like the first case. Given a class C with Deconstructor(out string a, out string b):
var c = new C();
var (h, i) = c;
(string j, string k) = c;
But the compiler won't use the deconstructor to implicitly convert it to a tuple:
// Cannot implicitly convert type 'C' to '(string a, string b)'
var (a, b) l = c;
Obviously you can mechanically write an implicit conversion based on the deconstructor:
public static implicit operator (string a, string b) (C c)
{
c.Deconstruct(out string a, out string b);
return (a, b);
}
Notwithstanding the visual similarity in the syntax between the deconstruction and assignment cases, assigning a reference to a tuple is not the same as deconstructing a class into variables and then putting them in a new tuple. However, you can implicitly convert (int x, int y) to (double x, double y). Value tuples are the kind of syntactic-sugar feature where it does what it looks like it does, and never mind the implementation details.
If I thought of this, the C# team thought of it, and if they chose not to add "magic" support for the implicit conversion, they had a good reason1.
Is there a positive reason why doing the implicit conversion automatically would have been a bad idea?
Or is it one of those features that just wasn't regarded as valuable enough to justify the cost?
Here's the code from that fiddle:
public class Program
{
public static void Main()
{
(string a, string b) = F();
(string a, string b) ab = F();
Console.WriteLine($"a: {a} b: {b} ab: {ab}");
var c = new C();
(string d, string e) = c;
// Cannot implicitly convert type 'C' to '(string a, string b)'
(string a, string b) f = c;
Console.WriteLine($"d: {d} e: {e} f: {f}");
// Covariance
(object c, object d) g = F();
// Implicit conversion
(double x, double y) t = G();
}
public static (string a, string b) F()
=> ("A", "B");
public static (int x, int y) G()
=> (0, 1);
}
public class C
{
public String A = "A";
public String B = "B";
public void Deconstruct(out String a, out String b)
{
a = A;
b = B;
}
}
1 The C# team may not be smarter than everybody, but I've never lost money betting they were at least as smart as me.
The ability to have deconstructs act like implicit converters was something that was asked for (by me, so I'm biased here) before C# 7 was released. The response from the team was (as I read it anyway) that it was asked for too near to the C# 7 release and would have taken too long to implement, so wasn't up for consideration. As it would now be a breaking change, it's not something that will ever happen.
Please see the "Allow Deconstruct and implicit operator to both support deconstruction and conversion to tuple types" roslyn repo issue for the actual discussion on the matter.
(string a, string b) ab declares a single variable of the tuple type (string a, string b) named ab. This lets you write ab.a or ab.b, but not a or b.
(string a, string b) f = c; tries to convert an unrelated C type to this tuple type. Unless you write a cast, there is no way for that to happen.
Specifically, as the name implies, destructuring only lets you assign to variables; it does not let you convert to an unrelated type.

Related Links

For Android this is a simple script which i want to modify for touch devices?
How can I get XMLRPC.NET to match perl speed?
NewtonSoft JArray - how to select multiple elements with LINQ
Intentionally cause a fatal exception
The controller for path '/Admin/Widget/ConfigureWidget' was not found or does not implement IController
Why Ilist is implementing from both Icollection& Ienumerable,eventhough Icollection:Ienumerable
Deserialize runtime created class
log4net implementation detail - custom appender
Setting one-to-one relationship
Calling a method of a class which is not the viewmodel using CallMethodAction
How to fire event out of threading mode
How to set up google-diff-match-patch C# library
How do I set two class properties from one SET method c#
Showing a short date according to users localId
Printing Label Brother P-Touch from C# script
issue with asp.net webApi routing with angularjs. (Multiple actions were found that match)

Categories

HOME
skype-for-business
azure-active-directory
teradata
sip
artifactory
msbi
ms-access-2010
angularjs-directive
meson-build
rethinkdb
osx-yosemite
elastalert
decoding
xmlhttprequest
watson-dialog
google-closure-compiler
airbnb
android-wifi
android-navigation-drawer
dev-c++
angular2-pipe
email-client
prepros
struts
priority-queue
orgchart
android-6.0-marshmallow
uibarbuttonitem
windows-10-mobile
bytebuffer
csproj
hierarchy
webspeech-api
javax
campaign-monitor
respect-validation
azure-storage-files
remap
django-tables2
cancan
htop
racket-student-languages
easy68k
disconnect
netlink
geokit
jigsaw
android-xmlpullparser
dcast
videoview
sdkman
windows-kernel
random-sample
tooltwist
pagecontrol
eula
mergecursor
mathics
touch-typing
uiblureffect
illegalargumentexception
yosemite
nsnotificationcenter
disparity-mapping
amzi-prolog
winrun4j
rssi
new-operator
adabas
friendly-id
sygic
infomaker
extensibility
android-library
dd4t
cocotron
blackberry-eclipse-plugin
event-propagation
sqlbuddy
commonsware
fileoutputstream
mismatch
nyromodal
xslt-grouping
newspeak
mysql-pconnect
content-delivery-network

Resources

Encrypt Message