On 2/16/07, Spitfire <timid.gentoo / gmail.com> wrote:
> Robert Dober wrote:
> >> class LifeForm
> >>    attr_reader :age, :name, :foo
> >>
> >>    def initialize(age,name,foo)
> >>      @age = age
> >>      @name = name
> >>      @foo = foo
> >
> >        freeze
> >
> > and you might add freeze here, now it becomes quite tough to change
> > the LifeForm object.
> > Personally I do not know any way to modify it now, but someone will
> > show us soon, I am quite sure ;)
> >
>    Sorry, I'm no expert in Ruby. So you have to explain what 'freeze'
> does???
>
Sure should have been clearer

freeze basically does not allow modification of the object anymore
I will demonstrate in irb
923/425 > irb
irb(main):001:0> class A
irb(main):002:1>    attr_reader :a
irb(main):003:1>    def initialize
irb(main):004:2>       @a=42
irb(main):005:2>    end
irb(main):006:1>    def change
irb(main):007:2>       @a = rand(43)
irb(main):008:2>    end
irb(main):009:1> end
=> nil
irb(main):010:0> a=A.new
=> #<A:0xb7d829dc @a=42>
irb(main):011:0> a.change
=> 30
irb(main):012:0> a.instance_variable_set("@a", 1764)
=> 1764
irb(main):013:0> a
=> #<A:0xb7d829dc @a=1764>
irb(main):014:0> a.freeze
=> #<A:0xb7d829dc @a=1764>
irb(main):015:0> a.change
TypeError: can't modify frozen object
        from (irb):7:in `change'
        from (irb):15
        from :0
irb(main):016:0>  a.instance_variable_set("@a", 1764)
TypeError: can't modify frozen object
        from (irb):16:in `instance_variable_set'
        from (irb):16
        from :0

David stated that this can be overcome with instance eval, I do not
know how though
irb(main):017:0> a.instance_eval do
irb(main):018:1*    @a=1
irb(main):019:1> end
TypeError: can't modify frozen object
        from (irb):18
        from (irb):17:in `instance_eval'
        from (irb):17
        from :0
Documentation states that a frozen object cannot be unfrozen.
Unfortunately you cannot freeze your whole object so maybe it would be
good to expose a ProxyObject

class Intern
  attr_accessor :a
  def initialize
    @a = 42
  end
end

class Proxy
  def initialize protect
    @protect = protect
    freeze
  end
  def a *args, &blk
    @protect.a *args, &blk
  end
  freeze
end

i = Intern.new
p = Proxy.new( i  )
puts p.a

begin
  p.a = 42
rescue
  puts "good"
end

begin
  class Proxy
    def p; @protect; end
  end
rescue
  puts "very good"
end

begin
  Proxy.send(:define_method, :p){
    @protect
  }
rescue
  puts "better"
end

begin
  class << Proxy
    define_method(:p){
      @protect
    }
  end
rescue
  puts "even better"
end



begin
  p.a = 42
rescue
  puts "still good"
end

now you have pretty much sealed your Intern objects as long as all
access you allow is by Proxy.
That might give an APi which is pretty much clear about access :)

>    Let me add more hypothetical requirements to my problem (sorry for
> not stating these initially!)
>
>    Lets consider that LifeForm has a property called 'Rank'. Now, this
> is a very critical property that I must make sure to retain consistent.
> LifeForm can also have offsprings, which are tied to it, say by a
> instance variable that points any LifeForm to its list of offspring
> LifeForm objects.
>
>    Now, the rank of a LifeForm is its distance from all its ancestors. I
> want a functionality such that whenever you create a LifeForm, the rank
> is set to '0'. Next, I want to make sure that when I add offsprings to
> an existing LifeForm, its depth gets updated automagically, without my
> intervention. More specifically, I want to have a feature by which
> LifeForm has a mechanism in the class, which allows to it set by itself
> the 'rank' of its instances. And, when I add a child, say through a
> method 'add_Child' (don't know if this is the ideal solution, but this
> is what I can think of!), it does something like this,
Of course you cannot freeze the whole object anymore but only some parts.
>
>    for each child in new_children_added
>         child.depth = child.depth + current.depth
>          # current refers to parent or current object
>    end
>
>    actually I want this to be carried out to all children newly added,
> their children and so on. So that the ranks of a LifeForm is always
> consistent! Hope I've conveyed exactly what I want.
>
>    Now I want to be able to only 'read' this rank, not modify it from
> outside the LifeForm class. Is this possible? If so, how do you design it?
> --
> _ _ _]{5pitph!r3}[_ _ _
> __________________________________________________
> "I'm smart enough to know that I'm dumb."
>    - Richard P Feynman
>
>


-- 
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important things.
-Anonymous