Array and instance variable problem?

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]

···

--
Posted via http://www.ruby-forum.com/.

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.

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

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

  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]

Kind regards

  robert

···

On 24.01.2007 11:34, Maxime Guilbot wrote:

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

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.

···

--
Posted via http://www.ruby-forum.com/.

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]]
##### show @indexes-id #####
24861230
##### show ids of Array elements #####
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

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.

···

--
Posted via http://www.ruby-forum.com/.

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

>>>>> 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

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.

···

--
Posted via http://www.ruby-forum.com/.