# Mutable member variables -- surprising behavior

**URL:** <https://www.ruby-forum.com/t/mutable-member-variables-surprising-behavior/134752>\
**Category:** Ruby\
**Created:** [April 14, 2008, 7:27pm UTC](https://www.ruby-forum.com/t/mutable-member-variables-surprising-behavior/134752 "2008-04-14T19:27:46Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [April 14, 2008, 7:27pm UTC](https://www.ruby-forum.com/t/mutable-member-variables-surprising-behavior/134752/1 "2008-04-14T19:27:46Z")

</div>

I noticed some surprising behavior in one of my Ruby programs, and am  
wondering what the rationale is. Basically,  
given read-only access to a member variable (using attr\_reader) of  
class Array, I can modify that Array by modifying (what I think should  
be) a local copy of it. Shouldn’t the accessor return a copy of the  
variable instead of a reference to it? Or is it standard practice to  
hand-write an accessor for arrays that returns a clone of the array?

#!/usr/bin/ruby

class Example  
attr\_reader :elems

def initialize  
@elems = []  
3.times { @elems \<\< Object.new }  
end

def to\_s  
@elems.inspect  
end  
end

e = Example.new  
puts e

# output is:

# -604282308

# [#Object:0xb7f6c450, #Object:0xb7f6c43c, #Object:0xb7f6c428]

list = e.elems  
puts list.object\_id

# output is: -604282308

list.delete\_at(0)

puts e

# output is

# -604282308

# [#Object:0xb7f6c43c, #Object:0xb7f6c428]

---

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [April 14, 2008, 7:36pm UTC](https://www.ruby-forum.com/t/mutable-member-variables-surprising-behavior/134752/2 "2008-04-14T19:36:37Z")

</div>

On Mon, Apr 14, 2008 at 1:25 PM, Adam B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> class Example  
> end  
> list.delete\_at(0)
> 
> puts e
> 
> # output is
> 
> # -604282308
> 
> # [#Object:0xb7f6c43c, #Object:0xb7f6c428]

You misunderstand what “attr\_reader” does. The “attr\_” methods simply  
generate setter / getter methods on your class for instance variables.

attr\_reader :variable

def variable; @variable; end

attr\_writer :variable

def variable=(val); @variable = val; end

attr\_accessor :variable creates both.

If you want something truely immutable, you have to #freeze it, but  
then it’s not changeable inside the class either.

If you’re really worried about this, you can manually do:

class Example

def initialize  
@elems = []  
3.times { @elems \<\< Object.new }  
end

def to\_s  
@elems.inspect  
end

# Always give a copy of the array, that way the internal @elems

# array is never changed.

def elems  
@elems.clone  
end  
end

Hope that helps.

Jason R.

---

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [April 14, 2008, 7:44pm UTC](https://www.ruby-forum.com/t/mutable-member-variables-surprising-behavior/134752/3 "2008-04-14T19:44:14Z")

</div>

On Apr 14, 2008, at 11:34 AM, Jason R. wrote:

> # Always give a copy of the array, that way the internal @elems
> 
> # array is never changed.
> 
> def elems  
> @elems.clone  
> end  
> end

does not work, neither does dup. both are rather shallow in ruby. if  
you _really_ want a copy you need

Marshal.load(Marshal.dump(@elems))

otherwise you’ll end up with subtle bugs when the array is cloned, but  
elements inside of it, or deeper, are not.

fyi.

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [April 14, 2008, 7:46pm UTC](https://www.ruby-forum.com/t/mutable-member-variables-surprising-behavior/134752/4 "2008-04-14T19:46:00Z")

</div>

On Apr 14, 11:25 am, Adam B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> class Example  
> end  
> list.delete\_at(0)
> 
> puts e
> 
> # output is
> 
> # -604282308
> 
> # [#Object:0xb7f6c43c, #Object:0xb7f6c428]

This was recently discussed on this list. See:  
[http://groups.google.com/group/comp.lang.ruby/browse\_thread/thread/18058b9f36bdd1a7/](http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/18058b9f36bdd1a7/)

But the short answer is: Yes, you’ll have to write your own accessor  
if you don’t want this behavior. All attr\_reader does is define the  
accessor, which just returns the object. You don’t get a setter  
method (elems=), but that doesn’t make the object immutable.

HTH,  
Chris

---

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [April 14, 2008, 8:08pm UTC](https://www.ruby-forum.com/t/mutable-member-variables-surprising-behavior/134752/5 "2008-04-14T20:08:28Z")

</div>

On Apr 14, 2008, at 12:02 PM, Jason R. wrote:

> Eep, yeah, I forgot about that. #dup and #clone won’t work, sorry for  
> that misinformation.

well they _might_ 😉

i’ve killed a lot of time over the years on that one ;-(

cheers.

a @ [http://codeforpeople.com/](http://codeforpeople.com/)

---

<div class="post-metadata">

**Author:** ![adambeazley](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/5f9b8f/32.png) [@adambeazley](https://www.ruby-forum.com/u/adambeazley)\
**Post date:** [April 14, 2008, 8:03pm UTC](https://www.ruby-forum.com/t/mutable-member-variables-surprising-behavior/134752/6 "2008-04-14T20:03:44Z")

</div>

On Mon, Apr 14, 2008 at 1:43 PM, ara.t.howard [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> > 
> 
> ## a @ [http://codeforpeople.com/](http://codeforpeople.com/)
> 
> we can deny everything, except that we have the possibility of being  
> better. simply reflect on that.  
> h.h. the 14th dalai lama

Eep, yeah, I forgot about that. #dup and #clone won’t work, sorry for  
that misinformation.

Jason
