When I began using Ruby I loved most of the things I saw. I made couple (1 , 2 ) of posts on some of those features that I'd like to see in C#. When I started re-visiting code I wrote sometime back my views started to change considerably. One of these was the parallel assignment constructs in Ruby.
At first it looks tempting and trivial. Let's see the classic example of swapping two variables. In C# you'd do something like
string a = "Abhinaba";string b = "Basu";string temp = a;a = b;b = temp;
string
a = b;
b = temp;
This can be done beautifully using Ruby parallel assignment with just one line and no need for any temporary placeholder.
a = "Abhinaba" b = "Basu" a, b = b, a
Parallel assignment works by evaluating all expressions in the right-hand-side before any assignements are made. After that all assignments are made. So the effect is as if all assignments are made is parallel.
x = 5 a, x, c = x, 3, x+= 1
In the code above the values after the assignment is a = 5, x = 3, c = 6. The expressions on the right are evaluated first, even though x is reset to 3 in the middle, it has no effect on the value assigned to c.
The other simple rule is that if there are more lvalues than rvalues then the additional lvalues are made nil (as in C# null) and if there are more rvalues than lvalues then the additional rvalues are ignored. Till this point it's fine. I went around to all the folks I generally bug like Ankur with my usual dictum that these kinds of expressions are cool and C# should support them. Since in C# is strongly typed also has value-types, we can fail compilation when number or type of lvalue does not match the corresponding rvalues.
But things in Ruby get complicated after this. This is specially true if the rvalue contains an array. See the following code snippets from Programming Ruby book
a = [1, 2, 3, 4] b, c = a # b == 1, c == 2 b, *c = a # b == 1, c == [2, 3, 4] b, c = 99, a # b == 99, c == [1, 2, 3, 4] b, *c = 99, a # b == 99, c == [[1, 2, 3, 4]] b, c = 99, *a # b == 99, c == 1 b, *c = 99, *a # b == 99, c == [1, 2, 3, 4]
So if the last lvalue is prefixed with an asterix as in *c then all the remaining values of the rvalues are converted to an array and assigned to c. Similarly if the last rvalue is an array and it is prefixed with an asterix as in *a, then it is expanded to its constituent values in place. If you think that this is getting complicated go figure out the following nested assignments
b, (c, d), e = 1,2,3,4 # b == 1, c == 2, d == nil, e == 3 b, (c, d), e = [1,2,3,4] # b == 1, c == 2, d == nil, e == 3 b, (c, d), e = 1,[2,3],4 # b == 1, c == 2, d == 3, e == 4 b, (c, d), e = 1,[2,3,4],5 # b == 1, c == 2, d == 3, e == 5 b, (c,*d), e = 1,[2,3,4],5 # b == 1, c == 2, d == [3, 4], e == 5
I did the unfortunate thing of using a complicated nested assignment in some code I wrote for incremental backup of my digital pictures. When I had to fix a bug in that code I had to go through the whole damn spec again!!!