Project

General

Profile

Actions

Bug #2422

closed

splat operator fails on array of 1 element

Added by raulparolari (Raul Parolari) over 14 years ago. Updated almost 13 years ago.

Status:
Rejected
ruby -v:
1.9.1
[ruby-core:27003]

Description

=begin
In Ruby 1.9.1:

a, b = *[ 137, 271 ] # a = 137; b = 271 # (as expected)

a = *[ 137 ] # a = [137 ] # (should be 137 !)

Definition of splat (Matz & Flanagan book, p.98): "the array elements replace the array in the original rvalue".
Works as defined in Ruby 1.8; fails in 1.9.1
=end

Actions #1

Updated by ujihisa (Tatsuhiro Ujihisa) over 14 years ago

  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)

=begin

=end

Actions #2

Updated by daz (Dave B) over 14 years ago

=begin
Tanaka Akira (on ruby-core) wrote:

On Thu, Dec 3, 2009 at 2:35 AM, Raul Parolari wrote:

Bug #2422: splat operator fails on array of 1 element
http://redmine.ruby-lang.org/issues/show/2422

In Ruby 1.9.1:

a, b = *[ 137, 271 ] # a = 137; b = 271 # (as expected)

a = *[ 137 ] # a = [137 ] # (should be 137 !)

The Ruby 1.9 behavior is simplified and more consistent.

% ruby -ve '
a = *[1,2,3]; p a
a = *[1,2]; p a
a = *[1]; p a
a = *[]; p a'
ruby 1.9.2dev (2009-09-24 trunk 25067) [i686-linux]
[1, 2, 3]
[1, 2]
[1]
[]

% ruby-1.8 -ve '
a = *[1,2,3]; p a
a = *[1,2]; p a
a = *[1]; p a
a = *[]; p a'
ruby 1.8.8dev (2009-10-15 revision 25343) [i686-linux]
[1, 2, 3]
[1, 2]
1
nil

Ruby 1.9 doesn't handle zero or one element array specially.

But Raul's example reveals inconsistency from 1.9 for a balanced LHS / RHS ...

puts 'ruby %s (%s) [%s]' % [RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PLATFORM]

a,b,c,d = *[1,2,3,4]
p [a,b,c,d]

a,b,c = *[1,2,3]
p [a,b,c]

a,b = *[1,2]
p [a,b]

a = *[1]
p [a]

=begin (output)

ruby 1.8.6 (2008-08-11) [i386-mswin32]
[1, 2, 3, 4]
[1, 2, 3]
[1, 2]
[1]

ruby 1.9.2 (2009-05-19) [i386-mswin32_90]
[1, 2, 3, 4]
[1, 2, 3]
[1, 2]
[[1]]

=end

a = *[1] (a = 1) results in a = [1]

--
daz

=end

Actions #3

Updated by katz (katz bo) over 14 years ago

=begin
I personally think *[1, 2, 3] should be always unpacked first.

a = *[1, 2, 3] #(unpack Array due to *) should be equal to:
a = 1, 2, 3 #(as Ruby is very smart) is equal to: (this is really the tricky part)
*a = 1, 2, 3 #which packs 1, 2, 3 into Array a. Hence is equal to
a = [1, 2, 3]

a = *[1] #(unpack Array due to *) should be equal to:
a = 1 #(again, Ruby is smart it won't read this as *a = 1)

a, b = *[1, 2] #the Array gets unpacked first, so we get:
a, b = 1, 2 #this behaves identical to the next line:
a, b = [1, 2] #Hence a = 1; b = 2

If my understanding is correct, then the 1.9 behavior is a bug(TM).

I'm a noob so don't expect me to know what I'm talking about :D.
=end

Actions #4

Updated by daz (Dave B) over 14 years ago

=begin

Tanaka Akira wrote:

2009/12/21 katz bo :

I personally think *[1, 2, 3] should be always unpacked first.

a = *[1, 2, 3] #(unpack Array due to *) should be equal to:
a = 1, 2, 3 #(as Ruby is very smart) is equal to: (this is really the tricky part)
*a = 1, 2, 3 #which packs 1, 2, 3 into Array a. Hence is equal to
a = [1, 2, 3]

a = *[1] #(unpack Array due to *) should be equal to:
a = 1 #(again, Ruby is smart it won't read this as *a = 1)

Your way cannot interpret a = *[].

a = *[]
a =

It is not a valid Ruby statement.

I would expect to see the value of the first element in the empty array
as 1.8.6 provides ...

puts 'ruby %s (%s) [%s]' % [RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PLATFORM]

a = *[]
p a

a = [][0]
p a

ruby 1.8.6 (2008-08-11) [i386-mswin32]

nil

nil

ruby 1.9.2 (2009-05-19) [i386-mswin32_90]

[]

nil

I understood your last reply to me about "a, =" in multiple assignment
with a single RHS but, to me, "a = 1" is multiple assignment with
balanced (single) LHS/RHS.

Producing an empty array from a splatted empty array seems unproductive. ;)

daz

=end

Actions #5

Updated by katz (katz bo) over 14 years ago

=begin
Dave B wrote:

Producing an empty array from a splatted empty array seems unproductive.
Agreed.

Tanaka Akira wrote:

2009/12/21 katz bo :

I personally think *[1, 2, 3] should be always unpacked first.

Your way cannot interpret a = *[].

a = *[]
a =

It is not a valid Ruby statement.

Why not think of this as a special case?
There's always something special about zeros and nils in my shallow opinion. :P

In fact, a = *[] should exactly be a = IMHO. And strictly speaking, a = *[] should not be a valid syntax at all.
But, this is Ruby!

What does Ruby do with a = *[] ? Let me illustrate an IMO proper way:
Ruby looks at *[] and goes, "Fine, let me unpack it."
Ruby unpacks *[].
Then Ruby goes, "Nothing? But I can't carry ! No.. not in an assignment! Wait.. Let's do it!"
Ruby marks it as nil.

One of the reasons why I think this special case should be handled this way, is the way Ruby handles parallel assignments:
a, b = [1] # => [1]
p a # => 1
p b # => nil
This is not the case, for example, in python. (It spits "ValueError: need more than 1 value to unpack" when you do a, b = [1]).
Since Ruby auto-pads the out-of-range elements as nil, we have a good reason to make Ruby automatically handle a = *[] in this way.

I also have a vague observation that the splatted array is actually dealt differently by the internal Ruby in some cases. Assignment is such a case.

COMMAND # OUTPUT # RETURN # NOTES

p # # => nil
p *[] # # => nil # Fits very well in my "unpack first" theory
p nil # nil # => nil
a = []; p a # [] # => [] # ruby 1.9; should both be nil IMO
a =
[]; p a # [] # => [] # ruby 1.9; should both be nil IMO; the space between * and [ is allowed!

Additionally, I find `return' fails my expectations in a similar way assignment does:

def foo; return *[]; end; foo # => [] # ruby 1.9; I have doubt: nil or []?
def bar; return *[1]; end; bar # => [1] # ruby 1.9; I was expecting 1
def baz; return [],[1]; end; baz # => [1]
def ban; return [1],[2]; end; ban # => [1, 2]
def boo; return *[1,2]; end; boo # => [1, 2]

We know that return packs multiple parameters into an array. This, combined with my "unpack first" theory, makes me think the first two results are not correct. But I don't know. Can't test it with ruby 1.8 since I don't have it installed.

Can somebody post the result to the code above for ruby 1.8?

=end

Actions #6

Updated by Eregon (Benoit Daloze) over 14 years ago

=begin
2009/12/21 katz bo

Issue #2422 has been updated by katz bo.

Dave B wrote:

Producing an empty array from a splatted empty array seems unproductive.
Agreed.

Tanaka Akira wrote:

2009/12/21 katz bo :

I personally think *[1, 2, 3] should be always unpacked first.

Your way cannot interpret a = *[].

a = *[]
a =

It is not a valid Ruby statement.

Why not think of this as a special case?
There's always something special about zeros and nils in my shallow
opinion. :P

In fact, a = *[] should exactly be a = IMHO. And strictly speaking, a =
*[] should not be a valid syntax at all.
But, this is Ruby!

What does Ruby do with a = *[] ? Let me illustrate an IMO proper way:
Ruby looks at *[] and goes, "Fine, let me unpack it."
Ruby unpacks *[].
Then Ruby goes, "Nothing? But I can't carry ! No.. not in an
assignment! Wait.. Let's do it!"
Ruby marks it as nil.

One of the reasons why I think this special case should be handled this
way, is the way Ruby handles parallel assignments:
a, b = [1] # => [1]
p a # => 1
p b # => nil
This is not the case, for example, in python. (It spits "ValueError: need
more than 1 value to unpack" when you do a, b = [1]).
Since Ruby auto-pads the out-of-range elements as nil, we have a good
reason to make Ruby automatically handle a = *[] in this way.

I also have a vague observation that the splatted array is actually dealt
differently by the internal Ruby in some cases. Assignment is such a case.

COMMAND # OUTPUT # RETURN # NOTES

p # # => nil
p *[] # # => nil # Fits very well in my "unpack first" theory
p nil # nil # => nil
a = []; p a # [] # => [] # ruby 1.9; should both be nil IMO
a =
[]; p a # [] # => [] # ruby 1.9; should both be nil IMO; the
space between * and [ is allowed!

Additionally, I find `return' fails my expectations in a similar way
assignment does:

def foo; return *[]; end; foo # => [] # ruby 1.9; I have doubt: nil
or []?
def bar; return *[1]; end; bar # => [1] # ruby 1.9; I was expecting 1
def baz; return [],[1]; end; baz # => [1]
def ban; return [1],[2]; end; ban # => [1, 2]
def boo; return *[1,2]; end; boo # => [1, 2]

We know that return packs multiple parameters into an array. This, combined
with my "unpack first" theory, makes me think the first two results are not
correct. But I don't know. Can't test it with ruby 1.8 since I don't have it
installed.

Can somebody post the result to the code above for ruby 1.8?

Here it is:
COMMAND # 1.9 vs 1.8

p # => nil
p *[] # => nil
p nil # => nil
a = []; p a # => [] vs nil
a =
[]; p a # => [] vs nil

These 2 last look very weird.


def foo; return *[]; end; foo # => [] vs nil
def bar; return *[1]; end; bar # => [1] vs 1

def baz; return [],[1]; end; baz # => [1] vs SyntaxError: compile error
(
(irb):4: syntax error, unexpected tSTAR, expecting tAMPER
def baz; return [],[1]; end; baz
^
(irb):4: syntax error, unexpected ';', expecting tCOLON2 or '[' or '.'
def baz; return [],[1]; end; baz
^
)

def ban; return [1],[2]; end; ban # => [1, 2] vs SyntaxError: compile
error
(
(irb):4: syntax error, unexpected tSTAR, expecting tAMPER
def ban; return [1],[2]; end; ban # => [1, 2]
^
(irb):4: syntax error, unexpected ';', expecting tCOLON2 or '[' or '.'
def ban; return [1],[2]; end; ban # => [1, 2]
^
)

def boo; return *[1,2]; end; boo # => [1, 2] vs [1, 2]

So here we clearly see how 1.9 is more 'safe' ...



2009/12/21 katz bo <>

Issue #2422 has been updated by katz bo.


Dave B wrote:
>Producing an empty array from a splatted empty array seems unproductive.
Agreed.

Tanaka Akira wrote:
> 2009/12/21 katz bo <>:
>> I personally think *[1, 2, 3] should be always unpacked first.
>
> Your way cannot interpret a = *[].
>
> a = *[]
> a =
>
> It is not a valid Ruby statement.

Why not think of this as a special case?
There's always something special about zeros and nils in my shallow opinion. :P

In fact, a = *[] should _exactly_ be a = IMHO. And strictly speaking, a = *[] should not be a valid syntax at all.
But, this is Ruby!

What does Ruby do with a = *[] ? Let me illustrate an IMO proper way:
Ruby looks at *[] and goes, "Fine, let me unpack it."
Ruby unpacks *[].
Then Ruby goes, "Nothing? But I can't _carry_ <nothing>! No.. not in an assignment! Wait.. Let's do it!"
Ruby marks it as nil.

One of the reasons why I think this special case should be handled this way, is the way Ruby handles parallel assignments:
a, b = [1] # => [1]
p a # => 1
p b # => nil
This is not the case, for example, in python. (It spits "ValueError: need more than 1 value to unpack" when you do a, b = [1]).
Since Ruby auto-pads the out-of-range elements as nil, we have a good reason to make Ruby automatically handle a = *[] in this way.

I also have a vague observation that the splatted array is actually dealt differently by the internal Ruby in some cases. Assignment is such a case.

# COMMAND    # OUTPUT # RETURN # NOTES
p            #        # => nil
p *[]        #        # => nil # Fits very well in my "unpack first" theory
p nil        # nil    # => nil
a = *[]; p a # []     # => []  # ruby 1.9; should both be nil IMO
a =* []; p a # []     # => []  # ruby 1.9; should both be nil IMO; the space between * and [ is allowed!

Additionally, I find `return' fails my expectations in a similar way assignment does:

def foo; return *[]; end;       foo # => []  # ruby 1.9; I have doubt: nil or []?
def bar; return *[1]; end;      bar # => [1] # ruby 1.9; I was expecting 1
def baz; return *[],*[1]; end;  baz # => [1]
def ban; return *[1],*[2]; end; ban # => [1, 2]
def boo; return *[1,2]; end;    boo # => [1, 2]

We know that return packs multiple parameters into an array. This, combined with my "unpack first" theory, makes me think the first two results are not correct. But I don't know. Can't test it with ruby 1.8 since I don't have it installed.

Can somebody post the result to the code above for ruby 1.8?


Here it is:
COMMAND # 1.9 vs 1.8

p                # => nil
p *[]            # => nil
p nil            # => nil
a = *[]; p a # => [] vs nil
a =* []; p a # => []  vs nil

These 2 last look very weird.

---------

def foo; return *[]; end; foo # => [] vs nil
def bar; return *[1]; end; bar # => [1] vs 1

def baz; return *[],*[1]; end;  baz # => [1] vs SyntaxError: compile error
(  
    (irb):4: syntax error, unexpected tSTAR, expecting tAMPER

    def baz; return *[],*[1]; end;  baz
                         ^
    (irb):4: syntax error, unexpected ';', expecting tCOLON2 or '[' or '.'
    def baz; return *[],*[1]; end;  baz
                             ^
)

def ban; return *[1],*[2]; end; ban # => [1, 2] vs SyntaxError: compile error
(
   (irb):4: syntax error, unexpected tSTAR, expecting tAMPER
   def ban; return *[1],*[2]; end; ban # => [1, 2]
                         ^
   (irb):4: syntax error, unexpected ';', expecting tCOLON2 or '[' or '.'
   def ban; return *[1],*[2]; end; ban # => [1, 2]
                             ^
)


def boo; return *[1,2]; end; boo # => [1, 2] vs [1, 2]

So here we clearly see how 1.9 is more 'safe' ...


=end

Actions #7

Updated by katz (katz bo) over 14 years ago

=begin
Thank you, Benoit Daloze.

I wrote:

What does Ruby do with a = *[] ? Let me illustrate an IMO proper way:
Ruby looks at *[] and goes, "Fine, let me unpack it."
Ruby unpacks *[].
Then Ruby goes, "Nothing? But I can't carry ! No.. not in an
assignment! Wait.. Let's do it!"
Ruby marks it as nil.

As now I think I understand assignment better, I'd like to correct myself a bit:

foo = *[]
When processing the above line, the Ruby interpreter does these things:

  1. First Ruby sees the left side of the assignment, i.e. foo =, and he points foo to nil.
  2. Then Ruby tries to evaluate the rvalue. Looking at the *, Ruby unpacks the array [].
  3. Ruby gets a little surprised when he finds it's empty in there.
  4. So Ruby (happily) does nothing, because there is nothing to re-point foo to.

That's the story. And this story tells me foo ends up nil.
What's the new story about ruby 1.9 if it's not a bug?
=end

Actions #8

Updated by mame (Yusuke Endoh) about 14 years ago

  • Status changed from Assigned to Rejected

=begin
Hi,

What's the new story about ruby 1.9 if it's not a bug?

If rvalue has a single expression, it returns the value itself.
If rvalue has multiple expressions (including splat), it returns
an array whose elements are each result.

If lvalue has a single variable, it assigns rvalue itself.
If lvalue has multiple variables, corresponding variable and
rvalue element are assigned respectively (if rvalue is not an
array, it is interpreted as singleton array).

Anyway, this is never a bug, It is contemplated, intended spec
change. Please accept reality.

You can register the same change request to Feature tracker,
but I strongly advise you to provide more concrete reason than
intuition.

--
Yusuke Endoh
=end

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0