Why do arrays work this way?

Hi folks

I'm using ruby 1.8.2 as comes with Mandriva 2005LE and get the following behaviour with arrays which doesn't seem logical to me.

In irb I do

irb(main):058:0* a=[1,2,3,4,5]
=> [1, 2, 3, 4, 5]

straight forward enough

irb(main):059:0> b=a
=> [1, 2, 3, 4, 5]
irb(main):060:0> c=a
=> [1, 2, 3, 4, 5]

I've set 2 more variables to equal 'a'

irb(main):061:0> b[3] = 'w'
=> "w"

I believe this changes index 3 in'b' to now be equal to 'w'

do
irb(main):062:0> b
=> [1, 2, 3, "w", 5]

that's exactly as I expected, BUT

irb(main):063:0> a
=> [1, 2, 3, "w", 5]
irb(main):064:0> c
=> [1, 2, 3, "w", 5]

so what's the logic behind 'a' & 'c' changing when I change 'b'.

Is this a bug? and if not what's the reasoning behind this behaviour please.

Best Rgds from confused of Heathfield
Nigel

···

__________________________________________________________________________
Disclaimer
Any opinions expressed in this email are not necessarily those of my wife

Nigel Wilkinson wrote:

Hi folks

I'm using ruby 1.8.2 as comes with Mandriva 2005LE and get the following behaviour with arrays which doesn't seem logical to me.

In irb I do

irb(main):058:0* a=[1,2,3,4,5]
=> [1, 2, 3, 4, 5]

straight forward enough

irb(main):059:0> b=a
=> [1, 2, 3, 4, 5]
irb(main):060:0> c=a
=> [1, 2, 3, 4, 5]

I've set 2 more variables to equal 'a'

irb(main):061:0> b[3] = 'w'
=> "w"

I believe this changes index 3 in'b' to now be equal to 'w'

do
irb(main):062:0> b
=> [1, 2, 3, "w", 5]

that's exactly as I expected, BUT

irb(main):063:0> a
=> [1, 2, 3, "w", 5]
irb(main):064:0> c
=> [1, 2, 3, "w", 5]

so what's the logic behind 'a' & 'c' changing when I change 'b'.

It's the same array in each case. The 3 variables each refer to it.

Hi folks

I'm using ruby 1.8.2 as comes with Mandriva 2005LE and get the following behaviour with arrays which doesn't seem logical to me.

[snip examples]

so what's the logic behind 'a' & 'c' changing when I change 'b'.

Is this a bug? and if not what's the reasoning behind this behaviour please.

In Ruby, everything is an object, but variables are just references to those objects. Your `b=a` sets b to reference the same object as a. Thus, when you make a change to one, they all change. Now, if you used `b=a.dup` b would be set to reference a copy of a, and the changes would not filter over.

Try playing around in irb as you have been doing, but calling object_id() on the arrays to seem which objects are the same.

Hope that helps.

James Edward Gray II

···

On Jun 17, 2005, at 6:51 PM, Nigel Wilkinson wrote:

When you make an assignment b = a, you assign the variable 'b' a
reference to the same array variable 'a' refers to. If you want to
have a copy of array a use dup method like

b = a.dup

Kent.

···

On 6/17/05, Nigel Wilkinson <nigel@waspz.co.uk> wrote:

Hi folks

I'm using ruby 1.8.2 as comes with Mandriva 2005LE and get the following
behaviour with arrays which doesn't seem logical to me.

In irb I do

irb(main):058:0* a=[1,2,3,4,5]
=> [1, 2, 3, 4, 5]

straight forward enough

irb(main):059:0> b=a
=> [1, 2, 3, 4, 5]
irb(main):060:0> c=a
=> [1, 2, 3, 4, 5]

I've set 2 more variables to equal 'a'

irb(main):061:0> b[3] = 'w'
=> "w"

I believe this changes index 3 in'b' to now be equal to 'w'

do
irb(main):062:0> b
=> [1, 2, 3, "w", 5]

that's exactly as I expected, BUT

irb(main):063:0> a
=> [1, 2, 3, "w", 5]
irb(main):064:0> c
=> [1, 2, 3, "w", 5]

so what's the logic behind 'a' & 'c' changing when I change 'b'.

Is this a bug? and if not what's the reasoning behind this behaviour please.

Best Rgds from confused of Heathfield
Nigel
__________________________________________________________________________
Disclaimer
Any opinions expressed in this email are not necessarily those of my wife

As in many modern languages (Java, most popularly, but I'd imagine Python, too), everything's a pointer, so to speak. If you want a copy, you should say b=a.dup, instead. Note, however, that not even that's perfect.

While this works:

irb(main):001:0> a=[1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> b=a.dup
=> [1, 2, 3, 4, 5]
irb(main):003:0> b[2]=7
=> 7
irb(main):004:0> a
=> [1, 2, 3, 4, 5]
irb(main):005:0> b
=> [1, 2, 7, 4, 5]
irb(main):006:0>

There is still a pitfall if the Objects that your Array contains are mutable (changeable):

irb(main):006:0> a=["hello","dog","cat"]
=> ["hello", "dog", "cat"]
irb(main):007:0> b=a.dup
=> ["hello", "dog", "cat"]
irb(main):008:0> b[2]="feline"
=> "feline"
irb(main):009:0> b[1].reverse!
=> "god"
irb(main):010:0> a
=> ["hello", "god", "cat"]
irb(main):011:0> b
=> ["hello", "god", "feline"]
irb(main):012:0>

Note that b[2]=... makes the new separate b Array point to a brand new String object, while b[1].reverse! modifies the existing String object -- the one that both a and b both point to. This is because Array#dup (and in general Object#dup) is a shallow copy. In other words, Object#dup is not "recursive" on the Objects inside.

Hope that helps, and hope it doesn't kill your buzz. :slight_smile:

Devin

a=[1,2,3,4,5]

This creates a specific object of class Array. "a" is a pointer
to the array-object. Just to be sure, I didn't say: "a" is the
array-object...

b=a

c=a

Now "b" and "c" point to the same object as "a".

so what's the logic behind 'a' & 'c' changing when I change
'b'.

I think you can now answer it yourself...

Is this a bug? and if not what's the reasoning behind this
behaviour please.

There's only one type for variables in Ruby: pointer. Pointer
to nothing (=nil) or pointer to an object. There's no such
thing as storing an object in a variable.

Have you read "Programming Ruby, The Pragmatic Programmer's
Guide" [1]?

Extra info: In Java, there's a difference between "int" and
"Integer". Variables of type "int" store direct values, whereas
variables of type "Integer" only store pointers, like in Ruby.
Pointers in Ruby are typeless and pointers in Java are of a
certain type.

gegroet,
Erik V. - http://www.erikveen.dds.nl/

[1] http://www.rubycentral.com/book/index.html

Nigel Wilkinson wrote:

irb(main):058:0> a=[1,2,3,4,5]; b = a; b[3] = 'w'; a
=> [1, 2, 3, "w", 5]

so what's the logic behind 'a' & 'c' changing when I change 'b'.

Is this a bug? and if not what's the reasoning behind this behaviour please.

In Ruby variables are just names for objects. If you do
   my_array = [1, 2, 3]
you name an array with the elements 1, 2 and 3 as my_array.

If you then do
   my_numbers = my_array
you just give the object named my_array another name (my_numbers). So what you did was just variable aliasing and nothing else.

Please note that in Ruby
   var += 5
is exactly the same as
   var = var + 5
which binds another name to the variable. This means that
   a = 5
   b = a
   b += 1
   [a, b] # => [5, 6]
because the objects didn't change at all -- you just decided to rename things.

Other languages with value semantics typically create a copy of the original object when you assign them to anything. This is typically done in Ruby like
   my_array = [1, 2, 3]
   my_copy = my_array.clone
which will then give you the behavior you intended:
   my_array[0] = :changed
   my_array # => [:changed, 2, 3]
   my_copy # => [1, 2, 3]

I think that Ruby's behavior is correct because languages where you explicitly have to specify that you want a reference to an object instead of a copy of it (like PHP used to do it even for values that are typically automatically passed by reference in the traditional languages like C++ and Java) cause more confusion. In Ruby you just give names to objects and ask them for a copy when you want one. It takes a short introduction (simply because languages that use pass-by-value somewhere are more common), but leads to less trouble later.

As in many modern languages (Java, most popularly, but I'd
imagine Python, too), everything's a pointer, so to speak.

Not everything in Java is a pointer. Compare "int" with
"Integer": a huge difference.

Sorry, I didn't realize that this is the Ruby news groups...

gegroet,
Erik V. - http://www.erikveen.dds.nl/

In article <pan.2005.06.18.00.13.48.594023@erikveen.dds.nl>, Erik Veenstra
wrote:
[...]

There's only one type for variables in Ruby: pointer. Pointer
to nothing (=nil) or pointer to an object.

[...]

nil is just an object.

Thanks everyone

Nigel

···

--On Saturday, June 18, 2005 09:04:28 +0900 Kent Sibilev <ksruby@gmail.com> wrote:

When you make an assignment b = a, you assign the variable 'b' a
reference to the same array variable 'a' refers to. If you want to
have a copy of array a use dup method like

b = a.dup

Kent.