Array and instance variable problem?


#1

Look at the code below, I got strange results, I know that there is a
problem in the code but I can’t find it. I expect to have an array like
this:

[[4, 4], [8, 1024], [1024, 1024], [1024, 1024], [1024, 1024], [1024,
1024], [1024, 1024], [1024, 1024], [1024, 1024], [1024, 1024]]

at the ouput of get_next_10…

Does someone has the idea?

Thanks a lot,
Maxime.

class Dummy
def initialize
@indexes = Array.new(2, 1)
end

def get_next
@indexes[0] = @indexes[0]*2
@indexes[1] = @indexes[1]*2

@indexes

end

def get_next_10
all = []
for i in 0…9
all << get_next
end
all
end
end
=> nil

d = Dummy.new
=> #<Dummy:0x33b198 @indexes=[1, 1]>

d.get_next_10
=> [[1024, 1024], [1024, 1024], [1024, 1024], [1024, 1024], [1024,
1024], [1024, 1024], [1024, 1024], [1024, 1024], [1024, 1024], [1024,
1024]]

d.get_next
=> [2048, 2048]

d.get_next
=> [4096, 4096]


#2

On 24.01.2007 11:34, Maxime Guilbot wrote:

Look at the code below, I got strange results, I know that there is a
problem in the code but I can’t find it. I expect to have an array like
this:

[[4, 4], [8, 1024], [1024, 1024], [1024, 1024], [1024, 1024], [1024,
1024], [1024, 1024], [1024, 1024], [1024, 1024], [1024, 1024]]

at the ouput of get_next_10…

Does someone has the idea?

Your problem is aliasing: you’re reusing the same @indexes over and over
again.

@indexes[1] = @indexes[1]*2

@indexes

Make that @indexes.dup or do get_next.dup in get_next_10.

=> nil
=> [2048, 2048]

d.get_next
=> [4096, 4096]

Kind regards

robert


#3

Maxime Guilbot schrieb:

def get_next
@indexes[0] = @indexes[0]*2
@indexes[1] = @indexes[1]*2

@indexes

end

Use “@indexes.dup” istead of “@indexes” as the last Statement,…

def get_next_10
all = []
for i in 0…9
all << get_next
end
all
end
end

…or “all << get_next.dup” instead of “all << get_next”.

In both cases you will end up with:

pp d.get_next_10

=>

[[2, 2],
[4, 4],
[8, 8],
[16, 16],
[32, 32],
[64, 64],
[128, 128],
[256, 256],
[512, 512],
[1024, 1024]]

The reason is, that you refer the same object in all Array positions
othewise.

Wolfgang Nádasi-Donner


#4

Thanks a lot for your answers, I got it :slight_smile:

I guessed that it was that kind of problem…
but I still don’t understand why it’s working if @indexes is not an
Fixnum, not an Array…

Anyway, your answers solved my problem,
Thanks again,
Maxime.


#5

Wolfgang, Thanks a lot for your detailed answer.

What I meant in my second message, is that when @indexes is a FixNum
(not an Array).
This code is working as expected:

#!/usr/local/bin/ruby

require ‘pp’
class Dummy
def initialize
@indexes = 1
end

def get_next
@indexes = @indexes*2

 @indexes

end

def get_next_10
all = []
for i in 0…9
all << get_next
end
all
end

def show_id
puts @indexes.object_id
end
end
d = Dummy.new

x = d.get_next_10
puts ‘##### show contents #####’
pp x
puts ‘##### show @indexes-id #####’
d.show_id
puts ‘##### show ids of Array elements #####’
x.each{|e|puts e.object_id}

The output I got is:

show contents

[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]

show @indexes-id

2049

show ids of Array elements

5
9
17
33
65
129
257
513
1025
2049

I am curious about this result, why is it not the same behaviour?

It’s also always the same @indexes which got into the array, right?

Thanks a lot for your patience!
Maxime.


#6

Maxime Guilbot schrieb:

but I still don’t understand why it’s working …

Take a look to the following example.

Code >>>>>

require ‘pp’
class Dummy
def initialize
@indexes = Array.new(2, 1)
end

def get_next
@indexes[0] = @indexes[0]*2
@indexes[1] = @indexes[1]*2

 @indexes

end

def get_next_10
all = []
for i in 0…9
all << get_next
end
all
end

def show_id
puts @indexes.object_id
end
end
d = Dummy.new

x = d.get_next_10
puts ‘##### show contents #####’
pp x
puts ‘##### show @indexes-id #####’
d.show_id
puts ‘##### show ids of Array elements #####’
x.each{|e|puts e.object_id}

Output >>>>>

show contents

[[1024, 1024],
[1024, 1024],
[1024, 1024],
[1024, 1024],
[1024, 1024],
[1024, 1024],
[1024, 1024],
[1024, 1024],
[1024, 1024],
[1024, 1024]]

show @indexes-id

24861230

show ids of Array elements

24861230
24861230
24861230
24861230
24861230
24861230
24861230
24861230
24861230
24861230

EOE >>>>>

Your original program pushes always the same object into the final array
(here
named “d”, and it ist the object, “@indexes” refers to. As a temporary
help
think in “Pointers”, than it shoud be clear.

Wolfgang Nádasi-Donner


#7

Thanks a lot Wolfgang, I completely understood!

Your explanation are great and very detailed, if I would have to score,
I would say 10/10 :wink:

Bests regards,
Maxime.


#8

Maxime Guilbot schrieb:

What I meant in my second message, is that when @indexes is a FixNum
(not an Array).
This code is working as expected:

In the code

def get_next
@indexes[0] = @indexes[0]*2
@indexes[1] = @indexes[1]*2

 @indexes

end

the contents of “@indexes” will be changed, but the “Array” object will
be the
same. In

def get_next
@indexes = @indexes*2

 @indexes

end

@indexes*2” will create a new object, which will be assigned to
@indexes
afterwards.

Conclusion: in case of the Array object you will end with the same
object with
changed contents (the same is valid for Hash objects, and may be valid
for
strings - see below), in case of the Fixnum object a new object will be
created
and referenced.

An example for class String to clarify this.

Code >>>>>

require ‘pp’
class Dummy
def initialize
@indexes = “a”
end

def get_next
  @indexes[0,1] = @indexes[0,1].succ

  @indexes
end

def get_next_10
  all = []
  for i in 0..9
    all << get_next
  end
  all
end

def show_id
  puts @indexes.object_id
end

end
d = Dummy.new

x = d.get_next_10
puts ‘##### show contents #####’
pp x
puts ‘##### show @indexes-id #####’
d.show_id
puts ‘##### show ids of Array elements #####’
x.each{|e|puts e.object_id}

Output >>>>>

show contents

[“k”, “k”, “k”, “k”, “k”, “k”, “k”, “k”, “k”, “k”]

show @indexes-id

24861400

show ids of Array elements

24861400
24861400
24861400
24861400
24861400
24861400
24861400
24861400
24861400
24861400

EoE >>>>>

If you change a line of code a little bit, something completely
different will
happen.

Parts of Code >>>>>

def get_next

@indexes[0,1] = @indexes[0,1].succ

  @indexes = @indexes.succ # <<<<<< Here is the minor change

  @indexes
end

Output >>>>>

show contents

[“b”, “c”, “d”, “e”, “f”, “g”, “h”, “i”, “j”, “k”]

show @indexes-id

24861380

show ids of Array elements

24861470
24861460
24861450
24861440
24861430
24861420
24861410
24861400
24861390
24861380

EoE >>>>>

Wolfgang Nádasi-Donner