On 2006-07-16, Dominik Bathon <dbatml / gmx.de> wrote:
> On Sat, 15 Jul 2006 23:15:05 +0200, Jeremy Henty <jeremy / chaos.org.uk>  
> wrote:
>
>> Given "def foo(*args) ..." I always expected the *members* of args
>> to be the arguments of the method call (and not copies of them).  I
>> did not expect args *itself* to be part of the Ruby call stack.  I
>> assumed it was just a temporary object created on the fly to give
>> me access to the method arguments.
>
> This definitely is the case for Ruby 1.8 and I can't reproduce your
> example with 1.8.4, only with 1.9. 

I am running 1.8.5-preview1 .  If I downgrade to 1.8.4 I get the
behaviour I first expected.  So my expectations were not that
ridiculous, which is comforting.  And I guess the answer to my
question "might this behaviour change" is clearly "yes"!  (Which means
I have some code to rewrite, /me sighs.)

> In 1.8 the arguments are stored in a C array in the FRAME struct and
> when splatting is used a new Ruby array is created every time:
>
> $ cat super_splat.rb
> class A
>    def foo(*a); p a, a.object_id; end
> end
>
> class B < A
>    def foo(*a); p a, a.object_id; a.shift; super; end
> end
>
> B.new.foo(1,2,3)

Under 1.8.4 :
[1, 2, 3]
-605563672
[1, 2, 3]
-605563762

Under 1.8.5 : 
[1, 2, 3]
-605295548
[2, 3]
-605295638

Is this an intentional change or a side-effect of something else?

> And even in 1.9 it actually is a different Ruby array:

Yes, the array is always a new VALUE (with a different
(RARRAY(self))->ptr).  What's changed is the relation between the C
array of method arguments that is copied when we call super, and the C
array that is wrapped by args.  It seems that in 1.8.4 the latter is a
copy of the former, so the call to super gets a copy of the array that
was originally passed to the current method, even if the contents of
args have subsequently changed.  In 1.8.5 they look to be the same, so
the call to super gets a copy of the current contents of args.

Regards, 

Jeremy Henty