On Wed, Jun 16, 2004 at 08:18:24PM +0900, Robert Klemme wrote:
> The cleanest might be to introduce something similar to C++'s keyword
> 'mutable', which allows instance variables to be changed even if the
> container is const (aka frozen).  But I don't like this approach
> because things soon get messy.  Constness is difficult to get right
> (not so much for the language but rather for users of the language)
> IMHO.

There's no need for this.  You can't change what object an instance
variable is referring to in a frozen object, but you can modify the
object itself.  So to get the effect you are looking for, you can write:

  class Foo
    Mutables = Struct.new(:foo)

    def initialize
      @mutables = Mutables.new(42)
    end

    def mutate(x)
      @mutables.foo = x
    end
  end

  f = Foo.new
  f.freeze
  f.mutate(10)
  p f

> Alternative solutions could make use of WeakReference somehow,
> although this is just a faint idea - nothing concrete.

If I understand you correctly you are talking about solving the problem
of wanting some part of the code to be able to modify an object but some
other part of the code to not be able to do this.  I've toyed with this
idea before.

One idea I had is to create a reference that unfreezes the object
before allowing you to use it.  In order for this to work, it has to set
Thread.critical=true (otherwise threads that are working with const
references would be able to modify the object).  The problem with this
is that the reference has know knowledge about the behavior of the
underlying object (it may make certain assumptions about frozen
instances; see [ruby-talk:8047]).

Another idea I had was to create a reference that only allows the user
to call read-only methods.  The reference has to "know" somehow which
methods are safe to allow; it can do this by freezing the object and
trying the operation (same problem as above) or by keeping a list of
safe operations (which can be a maintenance headache, plus there's the
question of what to do when the user calls #to_s on a reference to a
String).

One problem in general with using delegates as references is that you
have something that looks like a real object but is not.  If you try to
pass a weakref to a string into a C extension that is expecting a
string, it won't work.

IMO the only sensible implementation would be to change the interpreter
to include two types of references: one that allows changes and another
that does not.  It's not a small change, and Matz has already rejected
this idea (see RCR#92 at http://rcrchive.net/rgarchive/rejected.html#rcr92 or
http://www.google.com/search?q=cache:dzj80Q78zgMJ:rubygarden.com/article.php%3Fsid%3D222+%22rcr+92%22&hl=en
if you want a threaded view of the discussion).

Lastly, I can definitely see some potential uses for this feature (e.g.
for safe.rb), but for most cases dup and/or freeze and/or the trick
mentioned above will work.  I'm not sure if it makes sense to complicate
a library or the interpreter for a feature that is rarely useful (though
the same argument could have been made about callcc).

Paul