[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

multiple values & variable assignment

Its Me

1/8/2005 4:30:00 AM

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

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

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

This is inconsistent. Instead I propose:
x,y,z = f #=> x=1,y=2,z=3 (as current)
x = f #=> x = 1 (CHANGE)
*x = f #=> x=[1, 2, 3] (CHANGE)
x, y = *f #=> an error (f on R.h.s. is not an array)
x, y, z = [1, 2, 3], 4, 5 #=> x=[1, 2, 3], y=4, z=5 (current)
x, y, z = [1, 2, 3] #=> x=[1, 2, 3], y=nil, z=nil (CHANGE)
*x = [1, 2, 3] #=> x = [[1, 2, 3]] (current)
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.


4 Answers

Robert Klemme

1/8/2005 1:25:00 PM

0


"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
^
from (irb):49
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]?

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:
> x,y=[1, 2], 3 #=> x=[1,2] and y[3], fine
> x,y=[1, 2] #=> x=1, y=2 : not fine
>
> This is inconsistent. Instead I propose:
> x,y,z = f #=> x=1,y=2,z=3 (as current)
> x = f #=> x = 1 (CHANGE)
> *x = f #=> x=[1, 2, 3] (CHANGE)
> x, y = *f #=> an error (f on R.h.s. is not an array)
> x, y, z = [1, 2, 3], 4, 5 #=> x=[1, 2, 3], y=4, z=5 (current)
> x, y, z = [1, 2, 3] #=> x=[1, 2, 3], y=nil, z=nil (CHANGE)
> *x = [1, 2, 3] #=> x = [[1, 2, 3]] (current)
> 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

robert

Charles Mills

1/8/2005 10:11:00 PM

0

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
> ^
> from (irb):49
> 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
irb> def yields
irb> yield(1,2)
irb> end
=> nil
irb> 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...

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

-Charlie

Its Me

1/10/2005 1:00:00 AM

0

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

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

> > 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
f(1, 2, 3) #=> ArgError: wrong num. of args
f([1, 2, 3]) #=> [1, 2, 3]

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

> >> x, = f

Ouch! I did not know that. But
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
method call: ... f(*x)
vs.
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

1/10/2005 9:26:00 AM

0


"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.
>
> "Robert Klemme" <bob.news@gmx.net> wrote
>
> > > 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
> f(1, 2, 3) #=> ArgError: wrong num. of args
> f([1, 2, 3]) #=> [1, 2, 3]
>
> def g(*x); puts x; end
> g(1, 2, 3) #=> [1, 2, 3]
>
> > >> x, = f
>
> Ouch! I did not know that. But
> 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
> method call: ... f(*x)
> vs.
> 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

robert