[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

why does this freeze not work?

konsu

2/16/2006 12:44:00 AM

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


4 Answers

rcoder@gmail.com

2/16/2006 1:08:00 AM

0

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

konsu

2/16/2006 1:37:00 AM

0

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" <rcoder@gmail.com> wrote in message
news:1140052087.338798.124690@o13g2000cwo.googlegroups.com...
> 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
>


David Vallner

2/16/2006 1:53:00 AM

0

Dna Š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 Vallner


Robert Klemme

2/16/2006 10:42:00 AM

0

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