From: Robert Klemme Date: 2007-02-17T00:45:17+09:00 Subject: Re: class design issues On 16.02.2007 14:35, 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??? It prevents further manipulation of an instance: irb(main):001:0> %w{foo bar bx}.shift => "foo" irb(main):002:0> x=Struct.new(:name).new("foo") => # name="foo"> irb(main):003:0> x.name = "bar" => "bar" irb(main):004:0> x.freeze => # name="bar"> irb(main):005:0> x.name = "foo" TypeError: can't modify frozen Struct from (irb):5:in `name=' from (irb):5 from :0 irb(main):006:0> x => # name="bar"> irb(main):007:0> s="foo" => "foo" irb(main):008:0> s << "bar" => "foobar" irb(main):009:0> s => "foobar" irb(main):010:0> s.freeze => "foobar" irb(main):011:0> s << "xxx" TypeError: can't modify frozen string from (irb):11:in `<<' from (irb):11 from :0 > Let me add more hypothetical requirements to my problem (sorry for not > stating these initially!) Right. Your new set of requirements rules out "freeze" as that won't allow for adding of children etc. > 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, > > for each child in new_children_added > child.depth = child.depth + current.depth > # current refers to parent or current object > end You have a tree data structure here (if you have multiple roots it's called a "forest"). This is one of the well researched and understood structures. You'll find plenty of implementations and information on the web. Actually when adding a child, I would go up recursively to the root of the tree and update the rank. Kind of: def add_child(ch) delta = rank + 1 # BFS because Ruby is not good at recursion q = [ch] until q.empty? obj = q.shift obj.rank += delta q.concat obj.children end end You could make method rank= protected to prevent accidental invocation from the outside. > 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. Yes. One solution is to calculate the rank on demand and only optimize this to a local variable if you have performance issues. That solution is much easier because then you can simply do def rank obj, r = self, 0 while obj r += 1 obj = obj.parent end r end This is slow but always consistent. > 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? See above for ideas. Although I would probably not spend too much efforts in making it impossible to change the value from the outside. There is always a way. Kind regards robert