Array and instance variable problem?

M

Maxime Guilbot

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

Robert Klemme

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
 
W

Wolfgang Nádasi-Donner

Maxime said:
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
 
M

Maxime Guilbot

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

Wolfgang Nádasi-Donner

Maxime said:
but I still don't understand why it's working ...

Take a look to the following example.

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}

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

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
 
M

Maxime Guilbot

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

Wolfgang Nádasi-Donner

Maxime said:
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.

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}

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

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

def get_next
# @indexes[0,1] = @indexes[0,1].succ
@indexes = @indexes.succ # <<<<<< Here is the minor change

@indexes
end

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

Wolfgang Nádasi-Donner
 
M

Maxime Guilbot

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top