# Why does this freeze not work?

**URL:** <https://www.ruby-forum.com/t/why-does-this-freeze-not-work/53890>\
**Category:** Ruby\
**Created:** [February 16, 2006, 1:49am UTC](https://www.ruby-forum.com/t/why-does-this-freeze-not-work/53890 "2006-02-16T01:49:23Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![konsu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/0ea827/32.png) [@konsu](https://www.ruby-forum.com/u/konsu)\
**Post date:** [February 16, 2006, 1:49am UTC](https://www.ruby-forum.com/t/why-does-this-freeze-not-work/53890/1 "2006-02-16T01:49:23Z")

</div>

hello,

i need to set an instance variable in my object once and make sure this  
variable is not changed afterwards. i tried the code below which i  
expected  
to fail with a TypeError but it happily outputs ‘2’. i kind of  
understand  
why it succeeds, i think it just creates another @id when i call id=()  
method, but is there a way to do what i want to do?

thanks  
konstantin

class C  
attr\_accessor :id

def initialize(id)  
@id = id  
@id.freeze  
end  
end

c = C.new(1)  
c.id = 2

puts c.id

---

<div class="post-metadata">

**Author:** ![konsu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/0ea827/32.png) [@konsu](https://www.ruby-forum.com/u/konsu)\
**Post date:** [February 16, 2006, 2:01am UTC](https://www.ruby-forum.com/t/why-does-this-freeze-not-work/53890/2 "2006-02-16T02:01:30Z")

</div>

Hi,

In message “Re: why does this freeze not work?”  
on Thu, 16 Feb 2006 09:48:28 +0900, “konsu” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
writes:

|i need to set an instance variable in my object once and make sure this  
|variable is not changed afterwards. i tried the code below which i expected  
|to fail with a TypeError but it happily outputs ‘2’. i kind of understand  
|why it succeeds, i think it just creates another @id when i call id=()  
|method, but is there a way to do what i want to do?

No. You have frozen a Fixnum object 1, not @id. Instance variables  
are attributes of an object, not objects by themselves. You have to  
freeze whole object C, or use attr\_reader instead of attr\_accessor.

```
						matz.

```

---

<div class="post-metadata">

**Author:** ![konsu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/0ea827/32.png) [@konsu](https://www.ruby-forum.com/u/konsu)\
**Post date:** [February 16, 2006, 2:10am UTC](https://www.ruby-forum.com/t/why-does-this-freeze-not-work/53890/3 "2006-02-16T02:10:34Z")

</div>

Freezing affects the object on which you call the ‘freeze’ method, not  
the context in which it’s assigned to a name. In your example, you’re  
simply freezing a Fixnum instance representing the number 1. Then, when  
you assign a new value to the ‘id’ instance attribute, you’re changing  
which object it points to, rather than overwriting the original object.

This is because variables in Ruby are references to objects, not chunks  
of memory. Object mutation happens via method call, not assignment.

If you were to freeze your instance of C, you would get behavior more  
like you expect:

c = C.new(1)  
c.freeze  
c.id = 2 # raises TypeError

If you only want to prevent the ‘id’ attribute from being overwritten,  
just declare it with ‘attr\_reader’, instead of ‘attr\_accessor’.

-Lennon

---

<div class="post-metadata">

**Author:** ![konsu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/0ea827/32.png) [@konsu](https://www.ruby-forum.com/u/konsu)\
**Post date:** [February 16, 2006, 2:55am UTC](https://www.ruby-forum.com/t/why-does-this-freeze-not-work/53890/4 "2006-02-16T02:55:52Z")

</div>

DÅ?a Å tvrtok 16 FebruÃ¡r 2006 02:38 konsu napÃ­sal:

> thank you. i understand.
> 
> then attr\_accessor seems to be the only way. but one can always re-open my  
> object and change the @id attribute… that is why i wanted to freeze the  
> reference variable and not the object itself.

The same person could also reopen your class, replace #initialize\_copy,  
and  
then dup your frozen object and play with it to his heart’s content.

If you design your object to be immutable, odds are noone will reopen  
and hack  
at it just to spite your design. And if it does happen, it probably  
means  
there’s something missing your API.

David V.

---

<div class="post-metadata">

**Author:** ![konsu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/0ea827/32.png) [@konsu](https://www.ruby-forum.com/u/konsu)\
**Post date:** [February 16, 2006, 11:44am UTC](https://www.ruby-forum.com/t/why-does-this-freeze-not-work/53890/5 "2006-02-16T11:44:17Z")

</div>

konsu wrote:

> thank you. i understand.
> 
> then attr\_accessor seems to be the only way. but one can always  
> re-open my object and change the @id attribute… that is why i  
> wanted to freeze the reference variable and not the object itself.

In your case simply change it to attr\_reader. That way the field will  
be  
set in the constructor and cannot be changed from the outside. No  
freezer  
needed.

```
robert
```

---

<div class="post-metadata">

**Author:** ![konsu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/0ea827/32.png) [@konsu](https://www.ruby-forum.com/u/konsu)\
**Post date:** [February 16, 2006, 2:40am UTC](https://www.ruby-forum.com/t/why-does-this-freeze-not-work/53890/6 "2006-02-16T02:40:44Z")

</div>

thank you. i understand.

then attr\_accessor seems to be the only way. but one can always re-open  
my  
object and change the @id attribute… that is why i wanted to freeze  
the  
reference variable and not the object itself.

konstantin

“rcoder” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote in message  
news:removed\_email\_address@domain.invalid…
