Tom Sawyer <transami / transami.net> writes:

> class Tt
>   #attr_accessor :h  # no access to h!
>   def initialize
>     @h = {}
>     @h['test'] = '1..'
>   end
>   def [](xp)        # only want to allow reading
>     @h[xp]
>   end
>   #def []=(xp, ap)  # no assignment allowed!
>   #  @h[xp] = [ap]
>   #end
> end
> tt = Tt.new


> tt['test'] << '..2'         # how come you can do me?
Of course it is valid, I would be surprised if it is not valid. In the
code above for class Tt, you didn't define any []= method. This means,
objects of class Tt does not respond to []=. But tt['test'] is not of
type Tt. It is of type String. So of course tt['test']<<'..2' is a
valid statement.

> tt['test'] = '1....2'       # if you can't do me!
Since Tt does not respond to []=, then this one is correctly invalid.

To make objects contained within @h readonly, you don't make the
container (Tt or @h) readonly. Instead you have to write a wrapper for
the objects within @h that limits access, or write an object that only
allows changes from the direct owner of the container (which is Tt).

Or if you want the easy way, use the dup/freeze as Kent suggested.

def [](xp)
  @h[xp].dup.freeze
end

>prob w/ freezing is as you said, it freezes up the instance on the
>inside too.

Which is why you dup it first.

>prob w/ dup is the loss of connection to the orig --later changes from
>within the class won't be reflected and changes on the outside will
>seemingly work enven though there is no actual reflection within.

If you want to maintain the connection, then you got to write a
wrapper for the objects within @h.

So, 
> it seems to me that the main point of accessors and the []= method is to
> control accessiblity to a class' instance variables. right? 

right

> but as this example shows, there are ways in which "back-doors"
>exist.

there is no backdoor. by using the accessor and the []= method, you
are controlling the class' instance variable. but once you give the
object that the instance variable refers to, all is game.

Perhaps, what you want is deep-freeze (similar to deep-copy). Then the
solution is similar to the deep-copy problem, you got to traverse each
object you control and wrap/freeze them.

YS.