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