Behavior of iterator methods

Hi all,

I am a Ruby-beginner.
I have some experience of C/C++ for several years.
It has been only one week since I started to learn Ruby.
Please tell me about the behavior of iterator methods.

At first, I did as bellow on the irb environment.

···

-------------------------------------------------------
irb(main):001:0> s = ["a", "b", "c"]
=> ["a", "b", "c"]
irb(main):002:0> s[0].object_id
=> 36971304
irb(main):003:0> s[1].object_id
=> 36971292
irb(main):004:0> s[2].object_id
=> 36971280
irb(main):005:0> s.each{|c| c.upcase!}
=> ["A", "B", "C"]
irb(main):006:0> p s
["A", "B", "C"]
=> nil
-------------------------------------------------------

Looking at this, I thought I can change the value of each element in
Array object through iterator methods.

However, when I did next as bellow, that behavior looked different.
-------------------------------------------------------
irb(main):007:0> a = [1,2,3]
=> [1, 2, 3]
irb(main):008:0> a[0].object_id
=> 3
irb(main):009:0> a[1].object_id
=> 5
irb(main):010:0> a[2].object_id
=> 7
irb(main):011:0> a.each{|i| i += 1}
=> [1, 2, 3]
irb(main):012:0> p a
[1, 2, 3]
=> nil

irb(main):013:0> a.each{|i| p i.object_id}
3
5
7
=> [1, 2, 3]
-------------------------------------------------------

I expected that Array#each method with the code block would change
contents of the Array object variable named 'a' into [2,3,4].
But it didn't. Why?

The object IDs of a[0], a[1], a[2] are shown through
the the code block of Array#each. So I thought if variable named 'i'
changed its value, that had to be reflected to the Array object 'a'.
But it didn't.

Why did this difference happened?

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

Just because you presented 2 totally different cases: in the first one you deal with strings, while in the second you have Fixnums. If you re-wrote your first case with iterators, you would realize that everything is exactly the same as with the direct modification:

s = [ 'a', 'b', 'c' ]
s.each do |item|
  item.upcase!
end

However, when you work with Fixnum literals, several things needs to be kept in mind:

- Fixnums are immutable, there's no bang (!) methods to change them in-place like you can do for strings with update!()

- Construct i += 1 in ruby is a syntax sugar for i = i + 1, so the result is a completely different Fixnum instance. Same is true for strings:

s = "a"
s += "a"

After the above s will be pointing to another instance of String class with value "aa", while

s << 'a'

will be pointing to the same instance of String with updated value 'aa'

Hope this makes sense to you,
Gennady.

···

On Sep 19, 2012, at 8:20 PM, takanobu maekawa wrote:

Hi all,

I am a Ruby-beginner.
I have some experience of C/C++ for several years.
It has been only one week since I started to learn Ruby.
Please tell me about the behavior of iterator methods.

At first, I did as bellow on the irb environment.
-------------------------------------------------------
irb(main):001:0> s = ["a", "b", "c"]
=> ["a", "b", "c"]
irb(main):002:0> s[0].object_id
=> 36971304
irb(main):003:0> s[1].object_id
=> 36971292
irb(main):004:0> s[2].object_id
=> 36971280
irb(main):005:0> s.each{|c| c.upcase!}
=> ["A", "B", "C"]
irb(main):006:0> p s
["A", "B", "C"]
=> nil
-------------------------------------------------------

Looking at this, I thought I can change the value of each element in
Array object through iterator methods.

However, when I did next as bellow, that behavior looked different.
-------------------------------------------------------
irb(main):007:0> a = [1,2,3]
=> [1, 2, 3]
irb(main):008:0> a[0].object_id
=> 3
irb(main):009:0> a[1].object_id
=> 5
irb(main):010:0> a[2].object_id
=> 7
irb(main):011:0> a.each{|i| i += 1}
=> [1, 2, 3]
irb(main):012:0> p a
[1, 2, 3]
=> nil

irb(main):013:0> a.each{|i| p i.object_id}
3
5
7
=> [1, 2, 3]
-------------------------------------------------------

I expected that Array#each method with the code block would change
contents of the Array object variable named 'a' into [2,3,4].
But it didn't. Why?

The object IDs of a[0], a[1], a[2] are shown through
the the code block of Array#each. So I thought if variable named 'i'
changed its value, that had to be reflected to the Array object 'a'.
But it didn't.

Why did this difference happened?

However, when you work with Fixnum literals, several things needs to be kept in mind:

- Fixnums are immutable, there's no bang (!) methods to change them in-place like you can do for strings with update!()

- Construct i += 1 in ruby is a syntax sugar for i = i + 1, so the result is a completely different Fixnum instance. Same is true for strings:

s = "a"
s += "a"

After the above s will be pointing to another instance of String class with value "aa", while

s << 'a'

will be pointing to the same instance of String with updated value 'aa'

This explain makes sence. I've understood.
Thank you very much.