Array and instance variable problem?

Discussion in 'Ruby' started by Maxime Guilbot, Jan 24, 2007.

  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]

    --
    Posted via http://www.ruby-forum.com/.
    Maxime Guilbot, Jan 24, 2007
    #1
    1. Advertising

  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.

    > 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
    Robert Klemme, Jan 24, 2007
    #2
    1. Advertising

  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
    Wolfgang Nádasi-Donner, Jan 24, 2007
    #3
  4. Thanks a lot for your answers, I got it :)

    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, Jan 24, 2007
    #4
  5. 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
    Wolfgang Nádasi-Donner, Jan 24, 2007
    #5
  6. 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, Jan 25, 2007
    #6
  7. 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
    Wolfgang Nádasi-Donner, Jan 25, 2007
    #7
  8. 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 ;)

    Bests regards,
    Maxime.


    --
    Posted via http://www.ruby-forum.com/.
    Maxime Guilbot, Jan 25, 2007
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Paul Carey

    Instance Variable vs Local Variable

    Paul Carey, Dec 3, 2003, in forum: Java
    Replies:
    3
    Views:
    800
    Chris Uppal
    Dec 3, 2003
  2. Gerry Sutton
    Replies:
    1
    Views:
    538
    Peter Otten
    Apr 16, 2005
  3. Prasanth
    Replies:
    5
    Views:
    710
    Prasanth
    May 17, 2010
  4. David Garamond
    Replies:
    5
    Views:
    245
    Ara.T.Howard
    Jun 8, 2004
  5. Leon Bogaert
    Replies:
    19
    Views:
    326
    Robert Klemme
    Mar 23, 2008
Loading...

Share This Page