# Parallel Assignments and Elegance/Complexity Ratio

**URL:** <https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414>\
**Category:** ruby-talk\
**Created:** [11 January 2011 14:29 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414 "2011-01-11T14:29:38Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kedar\_Mhaswade](https://avatars.discourse-cdn.com/v4/letter/k/ee7513/32.png) [@Kedar\_Mhaswade](https://rubytalk.org/u/Kedar_Mhaswade)\
**Post date:** [11 January 2011 14:29 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/1 "2011-01-11T14:29:38Z")

</div>

In SICP, I read that "Programs should be written for people to read, and  
only incidentally for machines to execute".

While reading David/Matz book, I stumbled upon parallel assignments and  
I thought the language was trying to be too flexible (adding complexity,  
at least for a newcomer). My head soon started  
spinning (when it reached a, (b, (c,d)) = 1, [2, [3, 4]] I was  
exhausted).

My experience is recorded here:

> **[Ruby Parallel Assignments](https://docs.google.com/document/d/1zpHvfO4be3UvjaxU7L5gEPXFMENcMmEz9qqIcecEzOg/edit?hl=en)**
>
> This is based on the book Ruby Programming Language by David and Matz Parallel assignment elegance-complexity analysis (Ruby 1.9+) # Description Parallel Assignment Equivalent Alternate Elegance/Complexity ratio of Parallel Assignment 1 Same...

Summary is, I should only spend time learning  
- x, y, z = 1, 2, 3 (# =\> x=1, y=1, z=3), and  
- x, y = y, x (# =\> swap x and y)

I gather that this might be a matter of taste and style, but are other  
variants used by community?

Thank you,  
Kedar

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [11 January 2011 15:30 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/2 "2011-01-11T15:30:44Z")

</div>

Just today I used

&nbsp;&nbsp;def =(\*idx, val)  
&nbsp;&nbsp;&nbsp;&nbsp;index\_check(idx)  
&nbsp;&nbsp;&nbsp;&nbsp;@data[idx] = val  
&nbsp;&nbsp;end

> <https://gist.github.com/rklemme/772827>

See also thread "Nooby question : multidimensional arrays.".

I find the pattern matching \_very\_ elegant. This also comes in handy  
in situations like this:

irb(main):001:0\> a = Array.new(10) { [rand(10), rand(10)] }  
=\> [[2, 3], [7, 8], [4, 0], [4, 6], [5, 2], [9, 9], [4, 2], [8, 5],  
[2, 6], [5, 9]]  
irb(main):002:0\> a.sort {|(a1,a2),(b1,b2)| x = a2 \<=\> b2; x == 0 ? a1  
\<=\> b1 : x}  
=\> [[4, 0], [4, 2], [5, 2], [2, 3], [8, 5], [2, 6], [4, 6], [7, 8],  
[5, 9], [9, 9]]

Although in this particular case you could also use

irb(main):004:0\> a.sort\_by {|arr| arr.reverse}  
=\> [[4, 0], [4, 2], [5, 2], [2, 3], [8, 5], [2, 6], [4, 6], [7, 8],  
[5, 9], [9, 9]]  
irb(main):005:0\> a.sort\_by {|x, y| [y, x]}  
=\> [[4, 0], [4, 2], [5, 2], [2, 3], [8, 5], [2, 6], [4, 6], [7, 8],  
[5, 9], [9, 9]]

Generally I'd say I don't use it overly often but when I use it it is  
really handy. With #inject it's also useful if you iterate through a  
collection of Arrays of known equal length:

irb(main):006:0\> a.inject(0) {|s,(x,y)| s + x + y}  
=\> 100

Kind regards

robert

> **···**
>
> On Tue, Jan 11, 2011 at 3:29 PM, Kedar Mhaswade \<kedar.mhaswade@gmail.com\> wrote:
> 
> > In SICP, I read that "Programs should be written for people to read, and  
> > only incidentally for machines to execute".
> > 
> > While reading David/Matz book, I stumbled upon parallel assignments and  
> > I thought the language was trying to be too flexible (adding complexity,  
> > at least for a newcomer). My head soon started  
> > spinning (when it reached a, (b, (c,d)) = 1, [2, [3, 4]] I was  
> > exhausted).
> > 
> > My experience is recorded here:  
> > [Ruby Parallel Assignments - Google Docs](https://docs1.google.com/document/d/1zpHvfO4be3UvjaxU7L5gEPXFMENcMmEz9qqIcecEzOg/edit?hl=en#)
> > 
> > Summary is, I should only spend time learning  
> > - x, y, z = 1, 2, 3 (# =\> x=1, y=1, z=3), and  
> > - x, y = y, x (# =\> swap x and y)
> > 
> > I gather that this might be a matter of taste and style, but are other  
> > variants used by community?
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Josh\_Cheek](https://avatars.discourse-cdn.com/v4/letter/j/e79b87/32.png) [@Josh\_Cheek](https://rubytalk.org/u/Josh_Cheek)\
**Post date:** [11 January 2011 19:58 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/3 "2011-01-11T19:58:16Z")

</div>

I don't use it very often, but when I do, it usually makes an elegant  
solution. I think part of the reason it doesn't seem that way is because you  
are playing with it in too sterile of an environment. For example, you rate  
"x, (y, (z, a))=[1, [2, [3, 4]]]" as lowest, suggesting it is equivalent to  
"x=1;y=2;z=3;a=4" but this is not true. If you are actually assigning with  
literals, you would, of course, use the equivalent way, but if your data  
comes in as nested arrays, then you can't assign like that, instead you have  
to do something like this:

def parallel(values)  
&nbsp;&nbsp;x, (y, (z, a))=values  
&nbsp;&nbsp;[x,y,z,a]  
end  
def alternative(values)  
&nbsp;&nbsp;x = values.shift  
&nbsp;&nbsp;values = values.shift  
&nbsp;&nbsp;y = values.shift  
&nbsp;&nbsp;values = values.shift  
&nbsp;&nbsp;z = values.shift  
&nbsp;&nbsp;a = values.shift  
&nbsp;&nbsp;[x,y,z,a]  
end  
parallel [1, [2, [3, 4]]] # =\> [1, 2, 3, 4]  
alternative [1, [2, [3, 4]]] # =\> [1, 2, 3, 4]

Now, I don't normally store data like that, so I haven't ever done anything  
quite that fancy, but I use arrays on the RHS on occasion. It might look  
something like this (though I don't normally store my data like this, either  
-- it's really hard to think of a decent example!).

$stdin = DATA  
while input = gets  
&nbsp;&nbsp;name , num = input.split  
&nbsp;&nbsp;puts "#{name.capitalize}'s favourite number is #{num}"  
end  
\_\_END\_\_  
josh 12  
bill 42  
sally 13  
ned 99  
clara 1000000

The alternative of  
name , num = input.split  
is  
values = input.split  
name = values.shift  
num = values

I consider the former to be much more elegant as it avoids a temporary  
variable.

> **···**
>
> On Tue, Jan 11, 2011 at 8:29 AM, Kedar Mhaswade \<kedar.mhaswade@gmail.com\>wrote:
> 
> > In SICP, I read that "Programs should be written for people to read, and  
> > only incidentally for machines to execute".
> > 
> > While reading David/Matz book, I stumbled upon parallel assignments and  
> > I thought the language was trying to be too flexible (adding complexity,  
> > at least for a newcomer). My head soon started  
> > spinning (when it reached a, (b, (c,d)) = 1, [2, [3, 4]] I was  
> > exhausted).
> > 
> > My experience is recorded here:
> > 
> > [Ruby Parallel Assignments - Google Docs](https://docs1.google.com/document/d/1zpHvfO4be3UvjaxU7L5gEPXFMENcMmEz9qqIcecEzOg/edit?hl=en#)
> > 
> > Summary is, I should only spend time learning  
> > - x, y, z = 1, 2, 3 (# =\> x=1, y=1, z=3), and  
> > - x, y = y, x (# =\> swap x and y)
> > 
> > I gather that this might be a matter of taste and style, but are other  
> > variants used by community?
> > 
> > Thank you,  
> > Kedar
> > 
> > --  
> > Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Kedar\_Mhaswade](https://avatars.discourse-cdn.com/v4/letter/k/ee7513/32.png) [@Kedar\_Mhaswade](https://rubytalk.org/u/Kedar_Mhaswade)\
**Post date:** [11 January 2011 18:54 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/4 "2011-01-11T18:54:00Z")

</div>

Robert Klemme wrote in post #973945:

> >

> **[Ruby Parallel Assignments](https://docs.google.com/document/d/1zpHvfO4be3UvjaxU7L5gEPXFMENcMmEz9qqIcecEzOg/edit?hl=en)**
>
> This Doc is private

> > Summary is, I should only spend time learning  
> > - x, y, z = 1, 2, 3 (# =\> x=1, y=1, z=3), and  
> > - x, y = y, x (# =\> swap x and y)
> > 
> > I gather that this might be a matter of taste and style, but are other  
> > variants used by community?
> 
> Just today I used
> 
> &nbsp;&nbsp;def =(\*idx, val)  
> &nbsp;&nbsp;&nbsp;&nbsp;index\_check(idx)  
> &nbsp;&nbsp;&nbsp;&nbsp;@data[idx] = val  
> &nbsp;&nbsp;end
> 
> [https://gist.github.com/772827](https://gist.github.com/772827)
> 
> See also thread "Nooby question : multidimensional arrays.".
> 
> I find the pattern matching \_very\_ elegant. This also comes in handy  
> in situations like this:

Maybe I am not understanding it, but I thought that elegance is because  
of splat operator (which I am sure I like). My gripe is about various  
forms of parallel assignment and semantic/syntactic complexity because  
of that. Or are you saying that once you say you need splat operator,  
all this complexity is inevitable (of course, I can work around it by  
not using it, but then how do you all use it?)

-Kedar

> **···**
>
> > On Tue, Jan 11, 2011 at 3:29 PM, Kedar Mhaswade \> \<kedar.mhaswade@gmail.com\> wrote:
> 
> > irb(main):001:0\> a = Array.new(10) { [rand(10), rand(10)] }  
> > =\> [[2, 3], [7, 8], [4, 0], [4, 6], [5, 2], [9, 9], [4, 2], [8, 5],  
> > [2, 6], [5, 9]]  
> > irb(main):002:0\> a.sort {|(a1,a2),(b1,b2)| x = a2 \<=\> b2; x == 0 ? a1  
> > \<=\> b1 : x}  
> > =\> [[4, 0], [4, 2], [5, 2], [2, 3], [8, 5], [2, 6], [4, 6], [7, 8],  
> > [5, 9], [9, 9]]
> > 
> > Although in this particular case you could also use
> > 
> > irb(main):004:0\> a.sort\_by {|arr| arr.reverse}  
> > =\> [[4, 0], [4, 2], [5, 2], [2, 3], [8, 5], [2, 6], [4, 6], [7, 8],  
> > [5, 9], [9, 9]]  
> > irb(main):005:0\> a.sort\_by {|x, y| [y, x]}  
> > =\> [[4, 0], [4, 2], [5, 2], [2, 3], [8, 5], [2, 6], [4, 6], [7, 8],  
> > [5, 9], [9, 9]]
> > 
> > Generally I'd say I don't use it overly often but when I use it it is  
> > really handy. With #inject it's also useful if you iterate through a  
> > collection of Arrays of known equal length:
> > 
> > irb(main):006:0\> a.inject(0) {|s,(x,y)| s + x + y}  
> > =\> 100
> > 
> > Kind regards
> > 
> > robert
> 
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Kedar\_Mhaswade](https://avatars.discourse-cdn.com/v4/letter/k/ee7513/32.png) [@Kedar\_Mhaswade](https://rubytalk.org/u/Kedar_Mhaswade)\
**Post date:** [11 January 2011 20:29 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/5 "2011-01-11T20:29:52Z")

</div>

> literals, you would, of course, use the equivalent way, but if your data  
> comes in as nested arrays, then you can't assign like that, instead you  
> have  
> to do something like this:
> 
> def parallel(values)  
> &nbsp;&nbsp;x, (y, (z, a))=values  
> &nbsp;&nbsp;[x,y,z,a]  
> end  
> def alternative(values)  
> &nbsp;&nbsp;x = values.shift  
> &nbsp;&nbsp;values = values.shift  
> &nbsp;&nbsp;y = values.shift  
> &nbsp;&nbsp;values = values.shift  
> &nbsp;&nbsp;z = values.shift  
> &nbsp;&nbsp;a = values.shift  
> &nbsp;&nbsp;[x,y,z,a]  
> end  
> parallel [1, [2, [3, 4]]] # =\> [1, 2, 3, 4]  
> alternative [1, [2, [3, 4]]] # =\> [1, 2, 3, 4]
> 
> Now, I don't normally store data like that, so I haven't ever done  
> anything  
> quite that fancy, but I use arrays on the RHS on occasion. It might look  
> something like this (though I don't normally store my data like this,  
> either  
> -- it's really hard to think of a decent example!).

Thank you for sharing the use case. In this case, it helps. But like you  
said, it seems like an answer in search of a question.

> $stdin = DATA  
> while input = gets  
> &nbsp;&nbsp;name , num = input.split  
> &nbsp;&nbsp;puts "#{name.capitalize}'s favourite number is #{num}"  
> end  
> ...
> 
> The alternative of  
> name , num = input.split  
> is  
> values = input.split  
> name = values.shift  
> num = values
> 
> I consider the former to be much more elegant as it avoids a temporary  
> variable.

This however is already covered by me as the first case (with HIGH  
elegance rating) since you are expecting the line to contain exactly two  
strings (and if it is not so, it's an exceptional situation) and hence  
the (expected) number of lvalues = number of rvalues. I do  
like/understand such application of parallel assignment.

Thanks, again!

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Joseph\_Lenton](https://avatars.discourse-cdn.com/v4/letter/j/45deac/32.png) [@Joseph\_Lenton](https://rubytalk.org/u/Joseph_Lenton)\
**Post date:** [15 January 2011 11:04 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/6 "2011-01-15T11:04:43Z")

</div>

Josh Cheek wrote in post #974019:

> > Kedar
> > 
> > --  
> > Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).
> 
> I don't use it very often, but when I do, it usually makes an elegant  
> solution. I think part of the reason it doesn't seem that way is because  
> you  
> are playing with it in too sterile of an environment. For example, you  
> rate  
> "x, (y, (z, a))=[1, [2, [3, 4]]]" as lowest, suggesting it is equivalent  
> to  
> "x=1;y=2;z=3;a=4" but this is not true. If you are actually assigning  
> with  
> literals, you would, of course, use the equivalent way, but if your data  
> comes in as nested arrays, then you can't assign like that, instead you  
> have  
> to do something like this:
> 
> def parallel(values)  
> &nbsp;&nbsp;x, (y, (z, a))=values  
> &nbsp;&nbsp;[x,y,z,a]  
> end

Instead you could also do:

x, y, z, a = values.flatten

Which avoids making you look like your writing in LISP.

For small stuff parrallel assignment makes it look elegant, but like any  
language feature it can be abused. Although I don't think I've ever  
actually found a case where I've wanted to use this. Especially when  
most of the time my 'x, y, z and a' variables are unrelated so I don't  
want to use them together in the same statement.

> **···**
>
> > On Tue, Jan 11, 2011 at 8:29 AM, Kedar Mhaswade \> \<kedar.mhaswade@gmail.com\>wrote:
> 
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Josh\_Cheek](https://avatars.discourse-cdn.com/v4/letter/j/e79b87/32.png) [@Josh\_Cheek](https://rubytalk.org/u/Josh_Cheek)\
**Post date:** [11 January 2011 21:37 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/7 "2011-01-11T21:37:50Z")

</div>

Sorry, I don't understand. In this example, the rhs values are contained in  
an Array, which you consider low elegance, in your first example the rhs  
values are discrete. I don't see how they are the same, I think this is an  
instance of your "x, y, z = [1, 2, 3]", which you consider to be low  
elegance.

> **···**
>
> On Tue, Jan 11, 2011 at 2:29 PM, Kedar Mhaswade \<kedar.mhaswade@gmail.com\>wrote:
> 
> > \> variable.  
> > \> I consider the former to be much more elegant as it avoids a temporary  
> > This however is already covered by me as the first case (with HIGH  
> > elegance rating) since you are expecting the line to contain exactly two  
> > strings (and if it is not so, it's an exceptional situation) and hence  
> > the (expected) number of lvalues = number of rvalues. I do  
> > like/understand such application of parallel assignment.

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [12 January 2011 08:13 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/8 "2011-01-12T08:13:27Z")

</div>

> Robert Klemme wrote in post #973945:
> 
> > >
> 
> [Ruby Parallel Assignments - Google Docs](https://docs1.google.com/document/d/1zpHvfO4be3UvjaxU7L5gEPXFMENcMmEz9qqIcecEzOg/edit?hl=en#)
> 
> > > Summary is, I should only spend time learning  
> > > - x, y, z = 1, 2, 3 (# =\> x=1, y=1, z=3), and  
> > > - x, y = y, x (# =\> swap x and y)
> > > 
> > > I gather that this might be a matter of taste and style, but are other  
> > > variants used by community?
> > 
> > Just today I used
> > 
> > def =(\*idx, val)  
> > index\_check(idx)  
> > @data[idx] = val  
> > end
> > 
> > [Multi Dimensional Array · GitHub](https://gist.github.com/772827)
> > 
> > See also thread "Nooby question : multidimensional arrays.".
> > 
> > I find the pattern matching \_very\_ elegant. This also comes in handy  
> > in situations like this:
> 
> Maybe I am not understanding it, but I thought that elegance is because  
> of splat operator (which I am sure I like).

The splat operator is just part of the game as Josh has tried to  
demonstrate. The real power comes from pattern matching which will  
even work with multiple levels of nesting. And the mechanism is the  
same for method and block arguments which gives you one powerful  
mechanism usable in several places.

> My gripe is about various  
> forms of parallel assignment and semantic/syntactic complexity because  
> of that. Or are you saying that once you say you need splat operator,  
> all this complexity is inevitable (of course, I can work around it by  
> not using it, but then how do you all use it?)

No, I am saying that parallel assignment is just a special case of the  
assignment mechanism that is also in effect for method and block  
arguments. And while I don't use the fancy variants often (as Josh)  
when I use it it yields an elegant solution that would be more  
cumbersome without it.

Kind regards

robert

> **···**
>
> On Tue, Jan 11, 2011 at 7:54 PM, Kedar Mhaswade \<kedar.mhaswade@gmail.com\> wrote:
> 
> > > On Tue, Jan 11, 2011 at 3:29 PM, Kedar Mhaswade \>\> \<kedar.mhaswade@gmail.com\> wrote:
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Colin\_Bartlett1](https://avatars.discourse-cdn.com/v4/letter/c/dbc845/32.png) [@Colin\_Bartlett1](https://rubytalk.org/u/Colin_Bartlett1)\
**Post date:** [12 January 2011 16:44 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/9 "2011-01-12T16:44:10Z")

</div>

> ... I find the pattern matching \_very\_ elegant. ... Generally I'd say  
> I don't use it overly often but when I use it it is really handy. ...

> I don't use it very often, but when I do, it usually makes an  
> elegant solution. I think part of the reason it doesn't seem that  
> way is because you are playing with it in too sterile of an environment.

That last sentence seems an accurate assessment of why it perhaps  
doesn't seem much use to you, and what Josh Cheek and Robert Klemme  
say about those situations where they use it seems appropriate,  
although I haven't personally used it in those types of situations  
because my Ruby use is relatively simple.

> ... This however is already covered by me as the first case (with HIGH  
> elegance rating) since you are expecting the line to contain exactly two  
> strings ... and hence the (expected) number of lvalues = number of rvalues.  
> I do like/understand such application of parallel assignment.

Strangely, that's the situation (number of lvalues == number of  
rvalues) when I definitely dislike its use (unless it might be  
necessary to ensure all the rvalues are calculated before any  
assignment takes place - might side effects make this necessary?), for  
two (and a quarter) reasons.

First, whenever I've benchmarked parallel assignment against  
individual assignment, I've found the parallel assignment somewhat  
slower. The swap is more elegant, but even that seems slower.

Second, parallel assignment can make it difficult to see what is being  
assigned to what. In the following, is it instantly obvious what e is  
being set to?  
# a, b, c, d, e, f, g, h = q, r, s, t, u, v, w, x  
If it is instantly obvious, try more l and r values and/or try longer  
variable names and/or values and/or split the assignment expression  
over multiple lines!

As an actual example, this from Date:  
&nbsp;&nbsp;def initialize(ajd=0, of=0, sg=ITALY)  
&nbsp;&nbsp;&nbsp;&nbsp;@ajd, @of, @sg = ajd, of, sg  
&nbsp;&nbsp;&nbsp;&nbsp;# ...  
&nbsp;&nbsp;end  
Admittedly it's easy here to see what's being assigned to what, but  
even so is that really better than the alternative just below? Is  
there a reason for using the parallel assignment in the actual  
example, other than aesthetics?  
&nbsp;&nbsp;def initialize(ajd=0, of=0, sg=ITALY)  
&nbsp;&nbsp;&nbsp;&nbsp;@ajd = ajd; @of = of; @sg = sg  
&nbsp;&nbsp;&nbsp;&nbsp;# ...  
&nbsp;&nbsp;end

The quarter is the positive side of the negative point of the second,  
that explicit individual assignment is easier visually/cognitively  
than parallel assignment.

\*\*\* benchmarks

require "benchmark"  
a = b = c = d = e = f = g = h = nil; x = y = nil  
kt = 1\_000\_000  
Benchmark.bm( 22 ) do |bm|  
&nbsp;&nbsp;bm.report( "parallel assignment" ) { kt.times{  
&nbsp;&nbsp;&nbsp;&nbsp;a, b, c, d, e, f, g, h = 17, 23, 13, 48, 42, 46, 26, 24 } }  
bm.report( "individual assignment" ) { kt.times{  
&nbsp;&nbsp;&nbsp;a = 17; b = 23; c = 13; d = 48; e = 42; f = 46; g = 26; h = 24 } }  
bm.report( "swap elegant" ) { kt.times{  
&nbsp;&nbsp;&nbsp;x = 113; y = 355; x, y = y, x } }  
bm.report( "swap messy" ) { kt.times{  
&nbsp;&nbsp;&nbsp;x = 113; y = 355; z = x; x = y; y = z } }  
end

Using Linux, Ruby 1.9.1, but I've had similar results on MS Windows.  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user system total real  
parallel assignment 0.630000 0.000000 0.630000 ( 0.635576)  
individual assignment 0.400000 0.000000 0.400000 ( 0.393652)  
swap elegant 0.500000 0.000000 0.500000 ( 0.506171)  
swap messy 0.300000 0.000000 0.300000 ( 0.298167)

MS Windows: ruby 1.9.1p430 (2010-08-16 revision 28998) [i386-mingw32]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user system total real  
parallel assignment 0.531000 0.000000 0.531000 ( 0.530000)  
individual assignment 0.327000 0.000000 0.327000 ( 0.335000)  
swap elegant 0.500000 0.000000 0.500000 ( 0.490000)  
swap messy 0.296000 0.000000 0.296000 ( 0.300000)

MS Windows: jruby 1.5.3 (ruby 1.8.7 patchlevel 249) (2010-09-28 7ca06d7)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Java HotSpot(TM) Client VM 1.6.0\_14) [x86-java]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user system total real  
parallel assignment 0.735000 0.000000 0.735000 ( 0.705000)  
individual assignment 0.460000 0.000000 0.460000 ( 0.460000)  
swap elegant 0.560000 0.000000 0.560000 ( 0.560000)  
swap messy 0.425000 0.000000 0.425000 ( 0.425000)

> **···**
>
> On Tue, Jan 11, 2011 at 3:30 PM, Robert Klemme \<shortcutter@googlemail.com\> wrote:  
> On Tue, Jan 11, 2011 at 7:58 PM, Josh Cheek \<josh.cheek@gmail.com\> wrote:  
> On Tue, Jan 11, 2011 at 8:29 PM, Kedar Mhaswade \<kedar.mhaswade@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Adam\_Prescott1](https://avatars.discourse-cdn.com/v4/letter/a/2acd7d/32.png) [@Adam\_Prescott1](https://rubytalk.org/u/Adam_Prescott1)\
**Post date:** [17 January 2011 21:17 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/10 "2011-01-17T21:17:37Z")

</div>

> \> def parallel(values)  
> \> x, (y, (z, a))=values  
> \> [x,y,z,a]  
> \> end
> 
> Instead you could also do:
> 
> x, y, z, a = values.flatten
> 
> Which avoids making you look like your writing in LISP.

These two bits of code are not the same thing.

a, (b, c) = [1, [2, [3, 4]]]

a #=\> 1  
b #=\> 2  
c #=\> [3, 4]

a, b, c = [1, [2, [3, 4]]].flatten

a #=\> 1  
b #=\> 2  
c #=\> 3

> **···**
>
> On Sat, Jan 15, 2011 at 11:04 AM, Joseph Lenton \<jl235@kent.ac.uk\> wrote:
> 
> > Josh Cheek wrote in post #974019:  
> > \> On Tue, Jan 11, 2011 at 8:29 AM, Kedar Mhaswade \> \> \<kedar.mhaswade@gmail.com\>wrote:  
> > \>  
> > \>\>  
> > \>\> Kedar  
> > \>\>  
> > \>\> --  
> > \>\> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).  
> > \>\>  
> > \>\>  
> > \> I don't use it very often, but when I do, it usually makes an elegant  
> > \> solution. I think part of the reason it doesn't seem that way is because  
> > \> you  
> > \> are playing with it in too sterile of an environment. For example, you  
> > \> rate  
> > \> "x, (y, (z, a))=[1, [2, [3, 4]]]" as lowest, suggesting it is equivalent  
> > \> to  
> > \> "x=1;y=2;z=3;a=4" but this is not true. If you are actually assigning  
> > \> with  
> > \> literals, you would, of course, use the equivalent way, but if your data  
> > \> comes in as nested arrays, then you can't assign like that, instead you  
> > \> have  
> > \> to do something like this:  
> > \>  
> > \> def parallel(values)  
> > \> x, (y, (z, a))=values  
> > \> [x,y,z,a]  
> > \> end
> > 
> > Instead you could also do:
> > 
> > x, y, z, a = values.flatten
> > 
> > Which avoids making you look like your writing in LISP.
> > 
> > For small stuff parrallel assignment makes it look elegant, but like any  
> > language feature it can be abused. Although I don't think I've ever  
> > actually found a case where I've wanted to use this. Especially when  
> > most of the time my 'x, y, z and a' variables are unrelated so I don't  
> > want to use them together in the same statement.
> > 
> > --  
> > Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Kedar\_Mhaswade](https://avatars.discourse-cdn.com/v4/letter/k/ee7513/32.png) [@Kedar\_Mhaswade](https://rubytalk.org/u/Kedar_Mhaswade)\
**Post date:** [11 January 2011 21:49 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/11 "2011-01-11T21:49:22Z")

</div>

> Sorry, I don't understand. In this example, the rhs values are contained  
> in  
> an Array, which you consider low elegance, in your first example the rhs  
> values are discrete. I don't see how they are the same, I think this is  
> an  
> instance of your "x, y, z = [1, 2, 3]", which you consider to be low  
> elegance.

Ah, you are right. I stand corrected. Thanks.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Kedar\_Mhaswade](https://avatars.discourse-cdn.com/v4/letter/k/ee7513/32.png) [@Kedar\_Mhaswade](https://rubytalk.org/u/Kedar_Mhaswade)\
**Post date:** [13 January 2011 01:57 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/12 "2011-01-13T01:57:55Z")

</div>

> > I do like/understand such application of parallel assignment.
> 
> Strangely, that's the situation (number of lvalues == number of  
> rvalues) when I definitely dislike its use (unless it might be  
> necessary to ensure all the rvalues are calculated before any  
> assignment takes place - might side effects make this necessary?), for  
> two (and a quarter) reasons.

Interesting (yeah, it's a matter of taste).  
But when number of variables is \<=3, it looks very readable and easily  
understandable.

> First, whenever I've benchmarked parallel assignment against  
> individual assignment, I've found the parallel assignment somewhat  
> slower. The swap is more elegant, but even that seems slower.

That's a good point, but it's judgmental based on how frequently the  
code gets called.

> # a, b, c, d, e, f, g, h = q, r, s, t, u, v, w, x  
> If it is instantly obvious, try more l and r values and/or try longer  
> variable names and/or values and/or split the assignment expression  
> over multiple lines!

Well, one can always abuse a feature. I think number of variables should  
be \<=3, e.g.  
a, b, c = q, r ,s  
@d, @e, @f = t(a), u(b), v(c) # ...

> As an actual example, this from Date:  
> &nbsp;&nbsp;def initialize(ajd=0, of=0, sg=ITALY)  
> &nbsp;&nbsp;&nbsp;&nbsp;@ajd, @of, @sg = ajd, of, sg  
> &nbsp;&nbsp;&nbsp;&nbsp;# ...  
> &nbsp;&nbsp;end  
> Admittedly it's easy here to see what's being assigned to what, but  
> even so is that really better than the alternative just below? Is  
> there a reason for using the parallel assignment in the actual  
> example, other than aesthetics?  
> &nbsp;&nbsp;def initialize(ajd=0, of=0, sg=ITALY)  
> &nbsp;&nbsp;&nbsp;&nbsp;@ajd = ajd; @of = of; @sg = sg  
> &nbsp;&nbsp;&nbsp;&nbsp;# ...  
> &nbsp;&nbsp;end
> 
> The quarter is the positive side of the negative point of the second,  
> that explicit individual assignment is easier visually/cognitively  
> than parallel assignment.

Yeah. And the (others') wisdom suggests that if and when you find a  
situation to apply it, it (usually) renders an elegant solution.

-Kedar

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Charles\_Nutter](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/charles_nutter/32/2567_2.png) [@Charles\_Nutter](https://rubytalk.org/u/Charles_Nutter)\
**Post date:** [14 January 2011 16:41 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/13 "2011-01-14T16:41:34Z")

</div>

Parallel assignment is generally slower than straight-up assignment in  
1.9 and JRuby because it stands up a full Ruby Array for the RHS and  
result of the entire assignment expression:

~/projects/jruby ➔ jruby -e "p((a, b, c = 1, 2, 3))"  
[1, 2, 3]

As you would expect this is a significant cost compared to just  
assigning the values directly. JRuby can improve this when it knows  
that the assignment is not being used as an expression:

~/projects/jruby ➔ jruby -rbenchmark -e "2.times{ puts  
Benchmark.measure { 10000000.times {a,b,c=1,2,3} } }"  
&nbsp;&nbsp;1.924000 0.000000 1.924000 ( 1.812000)  
&nbsp;&nbsp;1.810000 0.000000 1.810000 ( 1.810000)

~/projects/jruby ➔ jruby -rbenchmark -e "2.times{ puts  
Benchmark.measure { 10000000.times {a,b,c=1,2,3; nil} } }"  
&nbsp;&nbsp;1.073000 0.000000 1.073000 ( 0.959000)  
&nbsp;&nbsp;0.884000 0.000000 0.884000 ( 0.884000)

There are also some implementations that "cheat" (I mean that in the  
nicest way possible) and don't bother producing that array return  
value at all, and they perform much better on parallel assignment as a  
result.

- Charlie

> **···**
>
> On Wed, Jan 12, 2011 at 10:44 AM, Colin Bartlett \<colinb2r@googlemail.com\> wrote:
> 
> > First, whenever I've benchmarked parallel assignment against  
> > individual assignment, I've found the parallel assignment somewhat  
> > slower. The swap is more elegant, but even that seems slower.

---

<div class="post-metadata">

**Author:** ![Colin\_Bartlett1](https://avatars.discourse-cdn.com/v4/letter/c/dbc845/32.png) [@Colin\_Bartlett1](https://rubytalk.org/u/Colin_Bartlett1)\
**Post date:** [14 January 2011 20:45 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/14 "2011-01-14T20:45:12Z")

</div>

> Parallel assignment is generally slower than straight-up assignment in  
> 1.9 and JRuby because it stands up a full Ruby Array for the RHS and  
> result of the entire assignment expression:

I'd assumed it was something like that. Thanks for the explanation.

> As you would expect this is a significant cost compared to just  
> assigning the values directly. JRuby can improve this when it knows  
> that the assignment is not being used as an expression:  
> ...  
> There are also some implementations that "cheat" (I mean that in the  
> nicest way possible)

I don't know if you've heard of the English magician Paul Daniels, but  
I'm very fond of a phrase he uses to contrast himself with some people  
who are, let us say, not self-admitted magicians. "I cheat, but I  
cheat honestly".

> and don't bother producing that array return value at all,  
> and they perform much better on parallel assignment as a result.

Cheating honestly, I think!

That's interesting, and the "cheating" idea hadn't ocurred to me. From  
the benchmarks below (similar to those you quoted; I did actually run  
the benchmarks twice, but the runs were very similar, so to avoid  
clutter I've only given one run) it seems MRC 1.9.1 is also cheating  
honestly if it can.

Now the only thing that's puzzling me is why the MRI 1.9.1 "cheating  
honestly" version of parallel assignment seems to be slightly but  
clearly faster than the MRI 1.9.1 single assignment!

require "benchmark"  
kt = 10\_000\_000  
nn = 1  
nn.times{ puts Benchmark.measure { kt.times {a,b,c=1,2,3 } } }  
nn.times{ puts Benchmark.measure { kt.times {a,b,c=1,2,3; nil} } }  
nn.times{ puts Benchmark.measure { kt.times {a = 1; b = 2; c = 3 } } }

jruby 1.5.3 (ruby 1.8.7 patchlevel 249) (2010-09-28 7ca06d7)  
&nbsp;&nbsp;(Java HotSpot(TM) Client VM 1.6.0\_14) [x86-java]  
&nbsp;&nbsp;3.038000 0.000000 3.038000 ( 3.007000)  
&nbsp;&nbsp;1.561000 0.000000 1.561000 ( 1.562000)  
&nbsp;&nbsp;1.558000 0.000000 1.558000 ( 1.558000)

ruby 1.9.1p430 (2010-08-16 revision 28998) [i386-mingw32]  
&nbsp;&nbsp;3.962000 0.000000 3.962000 ( 3.963000)  
&nbsp;&nbsp;1.747000 0.000000 1.747000 ( 1.741000)  
&nbsp;&nbsp;2.106000 0.000000 2.106000 ( 2.105000)

> **···**
>
> On Fri, Jan 14, 2011 at 4:41 PM, Charles Oliver Nutter \<headius@headius.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Charles\_Nutter](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/charles_nutter/32/2567_2.png) [@Charles\_Nutter](https://rubytalk.org/u/Charles_Nutter)\
**Post date:** [15 January 2011 02:06 UTC](https://rubytalk.org/t/parallel-assignments-and-elegance-complexity-ratio/61414/15 "2011-01-15T02:06:31Z")

</div>

> Now the only thing that's puzzling me is why the MRI 1.9.1 "cheating  
> honestly" version of parallel assignment seems to be slightly but  
> clearly faster than the MRI 1.9.1 single assignment!

Yes, that is a bit baffling! I have no explanation for that. As you  
can see in JRuby, the times for the non-expression parallel assignment  
and the normal assignment are roughly the same.

> require "benchmark"  
> kt = 10\_000\_000  
> nn = 1  
> nn.times{ puts Benchmark.measure { kt.times {a,b,c=1,2,3 } } }  
> nn.times{ puts Benchmark.measure { kt.times {a,b,c=1,2,3; nil} } }  
> nn.times{ puts Benchmark.measure { kt.times {a = 1; b = 2; c = 3 } } }
> 
> jruby 1.5.3 (ruby 1.8.7 patchlevel 249) (2010-09-28 7ca06d7)  
> (Java HotSpot(TM) Client VM 1.6.0\_14) [x86-java]  
> 3.038000 0.000000 3.038000 ( 3.007000)  
> 1.561000 0.000000 1.561000 ( 1.562000)  
> 1.558000 0.000000 1.558000 ( 1.558000)

FWIW, you'd get better results here if you ran a couple iterations,  
and of course if you specified --server it's significantly better...

~/projects/jruby ➔ jruby -v passign.rb  
jruby 1.6.0.RC1 (ruby 1.8.7 patchlevel 330) (2011-01-14 da2bb9d) (Java  
HotSpot(TM) Client VM 1.6.0\_22) [darwin-i386-java]  
&nbsp;&nbsp;1.952000 0.000000 1.952000 ( 1.839000)  
&nbsp;&nbsp;1.784000 0.000000 1.784000 ( 1.784000)  
&nbsp;&nbsp;1.796000 0.000000 1.796000 ( 1.796000)  
&nbsp;&nbsp;0.919000 0.000000 0.919000 ( 0.919000)  
&nbsp;&nbsp;0.865000 0.000000 0.865000 ( 0.865000)  
&nbsp;&nbsp;0.856000 0.000000 0.856000 ( 0.856000)  
&nbsp;&nbsp;0.961000 0.000000 0.961000 ( 0.961000)  
&nbsp;&nbsp;0.924000 0.000000 0.924000 ( 0.924000)  
&nbsp;&nbsp;0.880000 0.000000 0.880000 ( 0.880000)

~/projects/jruby ➔ jruby --server -v passign.rb  
jruby 1.6.0.RC1 (ruby 1.8.7 patchlevel 330) (2011-01-14 da2bb9d) (Java  
HotSpot(TM) Server VM 1.6.0\_22) [darwin-i386-java]  
&nbsp;&nbsp;1.388000 0.000000 1.388000 ( 1.324000)  
&nbsp;&nbsp;1.086000 0.000000 1.086000 ( 1.086000)  
&nbsp;&nbsp;1.034000 0.000000 1.034000 ( 1.034000)  
&nbsp;&nbsp;0.522000 0.000000 0.522000 ( 0.522000)  
&nbsp;&nbsp;0.500000 0.000000 0.500000 ( 0.500000)  
&nbsp;&nbsp;0.491000 0.000000 0.491000 ( 0.491000)  
&nbsp;&nbsp;0.517000 0.000000 0.517000 ( 0.517000)  
&nbsp;&nbsp;0.485000 0.000000 0.485000 ( 0.485000)  
&nbsp;&nbsp;0.496000 0.000000 0.496000 ( 0.496000)

> **···**
>
> On Fri, Jan 14, 2011 at 2:45 PM, Colin Bartlett \<colinb2r@googlemail.com\> wrote:
