This project is read-only.

Destructuring assignments and implicitly typed array literals

Topics: C# Language Design
Jun 26, 2014 at 2:12 PM
The current syntax for implicitly typed array literals is
new [] { 1, 2, 4 }
Which, I believe, can be harmlessly reduced to [1, 2, 4].

Deconstructing assignments are operations like
[a, b] = [1, 2]
(such stuff is already available in JS, see here)

with possible usages like
[login, password] = File.ReadAllLines("./account.txt");
[a, b] = [b, a]; //swapping using an implicitly typed array literal
Generally this feature will be useful in cases of non-structured data deserialization with output to explicitly specified variables. Notice the possibility of skipping values in expressions like
[a, , b] = [1, 2, 3];
Similarily, it would be great to have such an option for tuples, i.e. we would be able to write,
var x = new Tuple<int, string>(5, "hello");
[p, q] = x;
, thus making lots of code dealing with old CSV files or string arrays in general more elegant.
Jun 27, 2014 at 4:20 PM
I don't think having the [1,2,3] syntax for array literals would be that easy, but deconstructing Tuples or swapping variables in a single line would clearly be a good thing.
However, having that syntax work on an array (or IEnumerable) whose size we don't know at compile-time may be seen as error-prone.
Jun 27, 2014 at 6:14 PM
I did not mean that having the [1,2,3] syntax for array literals should be easy, I just stated that such syntax would be a good thing. Though I fail to see what exactly would be that hard about it, as well as I don't see the problem with throwing an exception when the requested deconstruction is not possible.
For example, one could always write something like arr[-1], or any other such expression not quite usual for C#, just to get an exception.

also, if we suppose that inlining variable declarations (SomeMethod(out int x, out int y)) is already implemented, we could think of deconstructing assignment expression as a syntactic sugar to an extension method call, given we have some extension method called Deconstruct<T1,T2..>(out T1 t1, out T2 t2..)
the [x,y] = arr expression can even be viewed as a call like arr.Deconstruct(out x, out y), and the [int x, int y] = arr should equal arr.Deconstruct(out int x, out int y).
...the situation becomes even more beautiful if we suppose that for this particular reason, out/ref params will be implemented (now this is where I'd say myself, "this would not be that easy", as it would require a speciall wrapper class, or some even more sophisticated approach)

also, regarding the comment about the syntax being error prone on an array or an IEnumerable, I'd like to point out that the current way of extracting values out of such containers does not look better: x = arr[0]; y = arr[1]; is error-prone in exactly the same way as [x,y] = arr, though the latter expression looks more elegant (to me, at least).

Anyway, I just named what I thought may become a useful part of the language. I do understand that the C# language is far more strict than JS (which is obviously a good thing), but I believe that such a feature will not harm this strictness.
Jun 27, 2014 at 7:10 PM
also, I'd like to point out that the swapping is a very simple case. Deconstructions allow more complex value transfers to be done in a single expression, like
  • a well-readable remap:
//now all of our chords are 5 semitones higher
[formerlyAm, formerlyDm, formerlyG, formerlyE] = [actuallyDm, actuallyGm, actuallyC, actuallyA]; 
  • a well-readable mapping:
//I'd use a built-in datetime parser anyway, but hey, this is just an example
[hours, minutes, seconds] = timeString.Split(':').Select(int.Parse).ToArray(); 
//not as perfect as it seems, because in most cases the data will be of different types
[name, surname, email, site] = line.Split('\t'); 
  • a permutation or a more general case of shifting values,
[x_3, x_2, x_1] = [x_2, x_1, x]; //now we're to recalculate our derivatives...
  • a lambda simplification,
//omitting tilting heads, so the roll component is ignored
allNpcs.ForEach(npc => [npc.Eyes.Yaw, npc.Eyes.Pitch] = GetYPR(npc,  myHorse)); //it is amazing!