From: Robert Dober Date: 2007-02-16T23:52:23+09:00 Subject: Re: class design issues On 2/16/07, Spitfire 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 => # irb(main):011:0> a.change => 30 irb(main):012:0> a.instance_variable_set("@a", 1764) => 1764 irb(main):013:0> a => # irb(main):014:0> a.freeze => # 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