Splat behavior with different versions of ruby

This is probably common knowledge, but the references I could find where annotated only in Japanese so I'm just not sure what is happening here:

···

#########################################################
#!/usr/bin/env ruby
puts "VERSION: #{RUBY_VERSION}"
puts "PLATFORM: #{RUBY_PLATFORM}"
h = { 'foo'=>3, 'bar'=>56 }
h.each do |*items|
   puts "items is of type #{items.class}"
   puts "1 = #{items[0]}, 2 = #{items[1]}"
end
#########################################################

vor-lord:/tmp> ruby r.rb
VERSION: 1.7.2
PLATFORM: i386-linux
items is of type Array
1 = bar, 2 = 56
items is of type Array
1 = foo, 2 = 3

vor-lord:/tmp> /usr/bin/ruby r.rb
VERSION: 1.8.0
PLATFORM: i386-linux-gnu
items is of type Array
1 = foo, 2 = 3
items is of type Array
1 = bar, 2 = 56

linux4:vor-lord/tmp> /opt/ictools/64bit/bin/ruby r.rb
VERSION: 1.8.1
PLATFORM: x86_64-linux-gnu
items is of type Array
1 = foo3, 2 =
items is of type Array
1 = bar56, 2 =

linux4:vor-lord/tmp> /usr/bin/ruby r.rb
VERSION: 1.6.8
PLATFORM: x86_64-linux-gnu
items is of type Array
1 = bar, 2 = 56
items is of type Array
1 = foo, 2 = 3

So out of 1.6.8, 1.7.2, 1.8.0, and 1.8.1, only 1.8.1 exhibits the behavior that I find counterintuitive. Is this the way it is supposed to work? If so, what is the rationale?

Hi --

This is probably common knowledge, but the references I could find where
annotated only in Japanese so I'm just not sure what is happening here:

[code examples]

So out of 1.6.8, 1.7.2, 1.8.0, and 1.8.1, only 1.8.1 exhibits the
behavior that I find counterintuitive. Is this the way it is supposed
to work? If so, what is the rationale?

There's a little bit on what might be a related topic at
<http://www.rubyist.net/~matz/slides/rc2003/mgp00022.html&gt;, and I
think there's been some discussion on ruby-core.

Here are what amount to some annotated notes to myself, which I hope
are reasonably accurate in their explanations. I'm definitely still
working my way through this. These are all 1.8.1.

  # Simple assignment to an array:
  $ ruby -e 'y = [1,2,3]; p y'
  [1, 2, 3]

  # Un-array the array:
  $ ruby -e 'y = [1,2,3]; p *y'
  1
  2
  3

  # This one means: "an unarrayed object (*y) is [1,2,3]",
  # so the object itself (y) must be [[1,2,3]]
  $ ruby -e '*y = [1,2,3]; p y'
  [[1, 2, 3]]

  # And this is the un-arrayed version of the above: assign
  # to *y, examine *y (the *'s essentially cancel out).
  $ ruby -e '*y = [1,2,3]; p *y'
  [1, 2, 3]

Similarly, with a non-array object:

  # *y is a string:
  $ ruby -e '*y = "abc"; p *y'
  "abc"

  # *y is an un-arrayed string; y is the array-wrapped version
  $ ruby -e '*y = "abc"; p y'
  ["abc"]

Given the above, one might say that *y always means: that which, when
wrapped in an array, is y". That raises the question, however, of
what happens when y is not an array. What seems to happen is that
* becomes a no-op:

  # In this example, un-arraying the object("abc") is a no-op,
  # because it's already as un-arrayed as it can get.
  $ ruby -e 'y = "abc"; p *y'
  "abc"

Also, the un-arraying process will not go so far as to dissolve the
last level of array into a bare list.

  # *[1,2,3] is "that which, when wrapped in an array, is [1,2,3]"
  # but un-array down to a bare list isn't allowed; therefore:
  $ ruby -e 'y = *[1,2,3]; p y'
  [1, 2, 3]

Whereas if there are enough levels to un-array the object comfortably,
that's what happens:

  # That which, when wrapped in an array, is [[1,2,3]],
  # namely [1,2,3].
  $ ruby -e 'y = *[[1,2,3]]; p y'
  [1, 2, 3]

Hoping this isn't too wildly misleading....

David

···

On Thu, 19 Aug 2004, Brett Williams wrote:

--
David A. Black
dblack@wobblini.net

Oh, and to answer your question... :slight_smile:

  lambda {|*items| ... } .call(['foo',56])

*items is ['foo',56], and is also "that which, when wrapped in an
array, is items" -- which means that items is ['foo',56] wrapped in an
array: [['foo',56]]. Hence items[0] is ['foo',56], and items[1] is
uninitialized.

David

···

On Fri, 20 Aug 2004, David A. Black wrote:

Hi --

On Thu, 19 Aug 2004, Brett Williams wrote:

> This is probably common knowledge, but the references I could find where
> annotated only in Japanese so I'm just not sure what is happening here:

[code examples]

> So out of 1.6.8, 1.7.2, 1.8.0, and 1.8.1, only 1.8.1 exhibits the
> behavior that I find counterintuitive. Is this the way it is supposed
> to work? If so, what is the rationale?

There's a little bit on what might be a related topic at
<http://www.rubyist.net/~matz/slides/rc2003/mgp00022.html&gt;, and I
think there's been some discussion on ruby-core.

Here are what amount to some annotated notes to myself, which I hope
are reasonably accurate in their explanations. I'm definitely still
working my way through this. These are all 1.8.1.

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

···

On Fri, 20 Aug 2004, David A. Black wrote:

Hi --

On Thu, 19 Aug 2004, Brett Williams wrote:

This is probably common knowledge, but the references I could find where annotated only in Japanese so I'm just not sure what is happening here:

[code examples]

So out of 1.6.8, 1.7.2, 1.8.0, and 1.8.1, only 1.8.1 exhibits the behavior that I find counterintuitive. Is this the way it is supposed to work? If so, what is the rationale?

There's a little bit on what might be a related topic at
<http://www.rubyist.net/~matz/slides/rc2003/mgp00022.html&gt;, and I
think there's been some discussion on ruby-core.

Here are what amount to some annotated notes to myself, which I hope
are reasonably accurate in their explanations. I'm definitely still
working my way through this. These are all 1.8.1.

Oh, and to answer your question... :slight_smile:

  lambda {|*items| ... } .call(['foo',56])

*items is ['foo',56], and is also "that which, when wrapped in an
array, is items" -- which means that items is ['foo',56] wrapped in an
array: [['foo',56]]. Hence items[0] is ['foo',56], and items[1] is
uninitialized.

Excellent, that explanation makes sense. This showed up in a coworker's code which stopped working under 1.8.1, and I couldn't see why it wouldn't work. Your explanation seems plausible.

Thanks!