Forum: Ruby why does this freeze not work?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
konsu (Guest)
on 2006-02-16 02:49
(Received via mailing list)
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
Yukihiro M. (Guest)
on 2006-02-16 03:01
(Received via mailing list)
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>
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.
rcoder (Guest)
on 2006-02-16 03:10
(Received via mailing list)
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 (Guest)
on 2006-02-16 03:40
(Received via mailing list)
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> wrote in message
news:removed_email_address@domain.invalid...
David V. (Guest)
on 2006-02-16 03:55
(Received via mailing list)
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.
Robert K. (Guest)
on 2006-02-16 12:44
(Received via mailing list)
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
This topic is locked and can not be replied to.