# Multiple values & variable assignment

**URL:** <https://rubytalk.org/t/multiple-values-variable-assignment/15667>\
**Category:** ruby-talk\
**Created:** [8 January 2005 04:31 UTC](https://rubytalk.org/t/multiple-values-variable-assignment/15667 "2005-01-08T04:31:26Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Its\_Me](https://avatars.discourse-cdn.com/v4/letter/i/958977/32.png) [@Its\_Me](https://rubytalk.org/u/Its_Me)\
**Post date:** [8 January 2005 04:31 UTC](https://rubytalk.org/t/multiple-values-variable-assignment/15667/1 "2005-01-08T04:31:26Z")

</div>

Why does  
&nbsp;&nbsp;&nbsp;&nbsp;def f; 1, 2, 3; end  
&nbsp;&nbsp;&nbsp;&nbsp;x,y,z = f  
give x=1, y=2, z=3

While  
&nbsp;&nbsp;&nbsp;&nbsp;x = f  
gives x=[1, 2, 3]?

Also:  
&nbsp;&nbsp;&nbsp;&nbsp;x,y=[1, 2], 3 #=\> x=[1,2] and y[3], fine  
&nbsp;&nbsp;&nbsp;&nbsp;x,y=[1, 2] #=\> x=1, y=2 : not fine

This is inconsistent. Instead I propose:  
&nbsp;&nbsp;&nbsp;&nbsp;x,y,z = f #=\> x=1,y=2,z=3 (as current)  
&nbsp;&nbsp;&nbsp;&nbsp;x = f #=\> x = 1 (CHANGE)  
&nbsp;&nbsp;&nbsp;&nbsp;\*x = f #=\> x=[1, 2, 3] (CHANGE)  
&nbsp;&nbsp;&nbsp;&nbsp;x, y = \*f #=\> an error (f on R.h.s. is not an array)  
&nbsp;&nbsp;&nbsp;&nbsp;x, y, z = [1, 2, 3], 4, 5 #=\> x=[1, 2, 3], y=4, z=5 (current)  
&nbsp;&nbsp;&nbsp;&nbsp;x, y, z = [1, 2, 3] #=\> x=[1, 2, 3], y=nil, z=nil (CHANGE)  
&nbsp;&nbsp;&nbsp;&nbsp;\*x = [1, 2, 3] #=\> x = [[1, 2, 3]] (current)  
&nbsp;&nbsp;&nbsp;&nbsp;x, y, z = \*[1, 2, 3] #=\> x=1, y=2, z=3 (current)

I am trying to write a getter that returns the instance variable + something  
special if that instance variable has not been initialized. Normal calls  
would ignore the second return value. The behavior above makes it difficult.  
Alternatives? Will this continue in 2.0?

Thanks.

btw: I think arrays and multiple values should be strictly separated  
syntactic classes.

---

<div class="post-metadata">

**Author:** ![Robert](https://avatars.discourse-cdn.com/v4/letter/r/e95f7d/32.png) [@Robert](https://rubytalk.org/u/Robert)\
**Post date:** [8 January 2005 13:26 UTC](https://rubytalk.org/t/multiple-values-variable-assignment/15667/2 "2005-01-08T13:26:25Z")

</div>

"itsme213" \<itsme213@hotmail.com\> schrieb im Newsbeitrag news:WkJDd.9898$ho.9719@fe2.texas.rr.com...

> Why does  
> &nbsp;&nbsp;&nbsp;def f; 1, 2, 3; end

You sure, that this is the code you use?

> > def f; 1, 2, 3; end

SyntaxError: compile error  
(irb):49: syntax error  
def f; 1, 2, 3; end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):49  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (null):0

I'll use

> > def f; return 1, 2, 3; end

=\> nil

> &nbsp;&nbsp;&nbsp;x,y,z = f  
> give x=1, y=2, z=3
> 
> While  
> &nbsp;&nbsp;&nbsp;x = f  
> gives x=[1, 2, 3]?

It's an optimization to save typing: if there are multiple values and on one side there is only one value "\*" is automatically prepended:

> > x = f

=\> [1, 2, 3]

> > x

=\> [1, 2, 3]

> > x = \*f

=\> [1, 2, 3]

> > x

=\> [1, 2, 3]

If you want just the first element you got to do

> > x, = f

=\> [1, 2, 3]

> > x

=\> 1

> Also:  
> &nbsp;&nbsp;&nbsp;x,y=[1, 2], 3 #=\> x=[1,2] and y[3], fine  
> &nbsp;&nbsp;&nbsp;x,y=[1, 2] #=\> x=1, y=2 : not fine
> 
> This is inconsistent. Instead I propose:  
> &nbsp;&nbsp;&nbsp;x,y,z = f #=\> x=1,y=2,z=3 (as current)  
> &nbsp;&nbsp;&nbsp;x = f #=\> x = 1 (CHANGE)  
> &nbsp;&nbsp;&nbsp;\*x = f #=\> x=[1, 2, 3] (CHANGE)  
> &nbsp;&nbsp;&nbsp;x, y = \*f #=\> an error (f on R.h.s. is not an array)  
> &nbsp;&nbsp;&nbsp;x, y, z = [1, 2, 3], 4, 5 #=\> x=[1, 2, 3], y=4, z=5 (current)  
> &nbsp;&nbsp;&nbsp;x, y, z = [1, 2, 3] #=\> x=[1, 2, 3], y=nil, z=nil (CHANGE)  
> &nbsp;&nbsp;&nbsp;\*x = [1, 2, 3] #=\> x = [[1, 2, 3]] (current)  
> &nbsp;&nbsp;&nbsp;x, y, z = \*[1, 2, 3] #=\> x=1, y=2, z=3 (current)
> 
> I am trying to write a getter that returns the instance variable + something  
> special if that instance variable has not been initialized. Normal calls  
> would ignore the second return value. The behavior above makes it difficult.  
> Alternatives? Will this continue in 2.0?
> 
> Thanks.
> 
> btw: I think arrays and multiple values should be strictly separated  
> syntactic classes.

IMHO we have to judge the costs of this change (broken code, confused coders :-)) vs. what we gain (more consistency). Dunno on what side the balance will come down though.

Kind regards

&nbsp;&nbsp;&nbsp;&nbsp;robert

---

<div class="post-metadata">

**Author:** ![Charles\_Mills1](https://avatars.discourse-cdn.com/v4/letter/c/85f322/32.png) [@Charles\_Mills1](https://rubytalk.org/u/Charles_Mills1)\
**Post date:** [8 January 2005 22:16 UTC](https://rubytalk.org/t/multiple-values-variable-assignment/15667/3 "2005-01-08T22:16:24Z")

</div>

Robert Klemme wrote:

> "itsme213" \<itsme213@hotmail.com\> schrieb im Newsbeitrag  
> news:WkJDd.9898$ho.9719@fe2.texas.rr.com...  
> \> Why does  
> \> def f; 1, 2, 3; end
> 
> You sure, that this is the code you use?
> 
> \>\> def f; 1, 2, 3; end  
> SyntaxError: compile error  
> (irb):49: syntax error  
> def f; 1, 2, 3; end  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (irb):49  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from (null):0
> 
> I'll use
> 
> \>\> def f; return 1, 2, 3; end  
> =\> nil
> 
> \> x,y,z = f  
> \> give x=1, y=2, z=3  
> \>  
> \> While  
> \> x = f  
> \> gives x=[1, 2, 3]?

You can think of it as return splat. Looks like Ruby 2.0 will give you  
piece of mind, see below...

> It's an optimization to save typing: if there are multiple values and

on one

> side there is only one value "\*" is automatically prepended:
> 
> \>\> x = f  
> =\> [1, 2, 3]  
> \>\> x  
> =\> [1, 2, 3]  
> \>\> x = \*f  
> =\> [1, 2, 3]  
> \>\> x  
> =\> [1, 2, 3]
> 
> If you want just the first element you got to do
> 
> \>\> x, = f  
> =\> [1, 2, 3]  
> \>\> x  
> =\> 1

(...)

I think this is the same issue as

> def yields  
> yield(1,2)  
> end

=\> nil

> yields { |a| puts a.inspect }

(irb):4: warning: multiple values for a block parameter (2 for 1)  
from (irb):2  
[1, 2]  
=\> nil

More info on this here:  
[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/23568](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/23568)

I know there is an English version of that post somewhere, but I can't  
find it on google...

-Charlie

---

<div class="post-metadata">

**Author:** ![Its\_Me](https://avatars.discourse-cdn.com/v4/letter/i/958977/32.png) [@Its\_Me](https://rubytalk.org/u/Its_Me)\
**Post date:** [10 January 2005 01:01 UTC](https://rubytalk.org/t/multiple-values-variable-assignment/15667/4 "2005-01-10T01:01:23Z")

</div>

But this is about more than just assignment, it is also about method calls  
vs. method defs.

> \> Why does  
> \> def f; 1, 2, 3; end
> 
> You sure, that this is the code you use?

My mistake, it was: def f; return 1, 2, 3; end

> It's an optimization to save typing: if there are multiple values and on

one

> side there is only one value "\*" is automatically prepended:

Ah. Unfortunate decision, because ...

x = 1, 2, 3 #=\> x = [1, 2, 3]  
\*x = 1, 2, 3 #=\> x = [1, 2, 3]

def f(x); puts x; end  
&nbsp;&nbsp;&nbsp;&nbsp;f(1, 2, 3) #=\> ArgError: wrong num. of args  
&nbsp;&nbsp;&nbsp;&nbsp;f([1, 2, 3]) #=\> [1, 2, 3]

def g(\*x); puts x; end  
&nbsp;&nbsp;&nbsp;&nbsp;g(1, 2, 3) #=\> [1, 2, 3]

> \>\> x, = f

Ouch! I did not know that. But  
&nbsp;&nbsp;&nbsp;&nbsp;def f(x,); end #=\> error.  
i.e. There is no such ',' syntax for method or proc parameters, just '\*'.

Method calls establish bindings. \*, \*\*, and & are nicely consistent and  
symmetric in  
&nbsp;&nbsp;&nbsp;&nbsp;method call: ... f(\*x)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vs.  
&nbsp;&nbsp;&nbsp;&nbsp;method definition: def f(\*x); end  
Since both method call and assignment establish variable bindings, I would  
suggest that:  
\* on lhs vs. rhs of assignement should parallel \* on call vs. def  
\*\* on lhs vs. rhs of assignment (if allowed) should parallel \*\* on call vs.  
def  
I'd say the same for '&', but can't think of a meaningful '&x = foo'.

> IMHO we have to judge the costs of this change (broken code, confused

coders

> :-)) vs. what we gain (more consistency). Dunno on what side the balance  
> will come down though.

Imho, a design decision that saves typing a single \*, and as a result makes  
binding variables via the assigment operation inconsistent with binding  
variables via a method call, is one that \_should\_ be changed for 2.0.

What do other Rubyists think of this proposal (assuming there was no issue  
of backward compatibility) ?

> **···**
>
> "Robert Klemme" \<bob.news@gmx.net\> wrote

---

<div class="post-metadata">

**Author:** ![Robert](https://avatars.discourse-cdn.com/v4/letter/r/e95f7d/32.png) [@Robert](https://rubytalk.org/u/Robert)\
**Post date:** [10 January 2005 09:31 UTC](https://rubytalk.org/t/multiple-values-variable-assignment/15667/5 "2005-01-10T09:31:21Z")

</div>

"itsme213" \<itsme213@hotmail.com\> schrieb im Newsbeitrag  
news:sskEd.20122$q4.3165@fe1.texas.rr.com...

> But this is about more than just assignment, it is also about method

calls

> vs. method defs.
> 
> \> \> Why does  
> \> \> def f; 1, 2, 3; end  
> \>  
> \> You sure, that this is the code you use?
> 
> My mistake, it was: def f; return 1, 2, 3; end
> 
> \> It's an optimization to save typing: if there are multiple values and

on

> one  
> \> side there is only one value "\*" is automatically prepended:
> 
> Ah. Unfortunate decision, because ...
> 
> x = 1, 2, 3 #=\> x = [1, 2, 3]  
> \*x = 1, 2, 3 #=\> x = [1, 2, 3]
> 
> def f(x); puts x; end  
> &nbsp;&nbsp;&nbsp;&nbsp;f(1, 2, 3) #=\> ArgError: wrong num. of args  
> &nbsp;&nbsp;&nbsp;&nbsp;f([1, 2, 3]) #=\> [1, 2, 3]
> 
> def g(\*x); puts x; end  
> &nbsp;&nbsp;&nbsp;&nbsp;g(1, 2, 3) #=\> [1, 2, 3]
> 
> \> \>\> x, = f
> 
> Ouch! I did not know that. But  
> &nbsp;&nbsp;&nbsp;&nbsp;def f(x,); end #=\> error.  
> i.e. There is no such ',' syntax for method or proc parameters, just

'\*'.

Yeah:

> > def f(x,\*) p x end

=\> nil

> > f 1,2,3

1  
=\> nil

> Method calls establish bindings. \*, \*\*, and & are nicely consistent and  
> symmetric in  
> &nbsp;&nbsp;&nbsp;&nbsp;method call: ... f(\*x)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vs.  
> &nbsp;&nbsp;&nbsp;&nbsp;method definition: def f(\*x); end  
> Since both method call and assignment establish variable bindings, I

would

> suggest that:  
> \* on lhs vs. rhs of assignement should parallel \* on call vs. def  
> \*\* on lhs vs. rhs of assignment (if allowed) should parallel \*\* on call

vs.

> def

I think "\*\*" is already taken:

> > -2 \*\* 3

=\> -8

Dunno whether it would be possible to extend the parser with a unary  
variant of it.

> I'd say the same for '&', but can't think of a meaningful '&x = foo'.
> 
> \> IMHO we have to judge the costs of this change (broken code, confused  
> coders  
> \> :-)) vs. what we gain (more consistency). Dunno on what side the

balance

> \> will come down though.
> 
> Imho, a design decision that saves typing a single \*, and as a result

makes

> binding variables via the assigment operation inconsistent with binding  
> variables via a method call, is one that \_should\_ be changed for 2.0.

I'm not sure whether I agree. After all assignment and method call are  
not exactly the same although I can see the common issue of variable  
binding. One of the differences is that the assignment has a result:

> > a,b,\*c=1,2,3,4

=\> [1, 2, 3, 4]

> > x=(a,b,\*c=1,2,3,4)

=\> [1, 2, 3, 4]

> > x

=\> [1, 2, 3, 4]

> What do other Rubyists think of this proposal (assuming there was no

issue

> of backward compatibility) ?

If it wasn't for the backward compatibility issue I think a change would  
lead to more consistence. At least nothing I see at the moment.

Regards

&nbsp;&nbsp;&nbsp;&nbsp;robert

> **···**
>
> > "Robert Klemme" \<bob.news@gmx.net\> wrote
