why does this freeze not work?

K

konsu

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
 
R

rcoder

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
 
K

konsu

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
 
D

David Vallner

D=C5=88a =C5=A0tvrtok 16 Febru=C3=A1r 2006 02:38 konsu nap=C3=ADsal:
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=
=20
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 h=
ack=20
at it just to spite your design. And if it does happen, it probably means=20
there's something missing your API.

David Vallner
 
R

Robert Klemme

konsu said:
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
 

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
474,202
Messages
2,571,057
Members
47,664
Latest member
RoseannBow

Latest Threads

Top