From: "ara.t.howard" Date: 2008-05-12T02:50:00+09:00 Subject: Re: Sharing variables between classes and instances On May 10, 2008, at 6:40 PM, David A. Black wrote: >> >> Hi all, >> >> What I'm trying to achieve: add a variable to a class. Fill it with >> data. Every nstance of that class should have access to the data in >> that >> variable. But I want every instance be able to modify that variable, >> without modifying the original value of the variable. > > I'm not sure what you mean exactly. Do you mean each instance should > have a copy of the object? If so, I would just do: > > class Tester > > def self.vars > @vars ||= [] > end > > def self.add_var(var) > self.vars << var > end > > def vars > @vars || self.class.vars > end > > def add_var(var) > @vars ||= self.class.vars.dup > vars << var > end > end > > That gives the results you expect in your test. > careful, any ruby code that uses 'dup' or clone has serious bugs 9 out of 10 times, in the case it doesn't meet the OP's *requirements* (although the simple test case passes) at all: cfp:~ > cat a.rb # # doesn't let instance modify the var without modifying the class var # Tester.add_var 'oops' t = Tester.new t.vars.first << ', this modifies the original' p Tester.vars #=> "oops, this modifies the original" # # and doesn't take a copy either # Tester.vars.clear Tester.add_var ['oops'] t = Tester.new t.vars.first << ', this modifies the original' p Tester.vars #=> [["oops", ", this modifies the original"]] BEGIN { class Tester def self.vars @vars ||= [] end def self.add_var(var) self.vars << var end def vars @vars || self.class.vars end def add_var(var) @vars ||= self.class.vars.dup vars << var end end } cfp:~ > ruby a.rb ["oops, this modifies the original"] [["oops", ", this modifies the original"]] you really need one of two things: a factory or a smarter copy algorithm: using a factory: cfp:~ > cat a.rb class Shares Factory = lambda { |var| case var.to_s when 'a' 'not shared' when 'b' 'but created fresh for class and instance cases' else end } def Shares.a @a ||= Factory['a'] end def a @a ||= Factory['a'] end end p Shares.a shares = Shares.new shares.a << ", but it's own copy" p Shares.a p shares.a cfp:~ > ruby a.rb "not shared" "not shared" "not shared, but it's own copy" or, using a smart copy method: cfp:~ > cat a.rb class Shares def Shares.a @a ||= 'not shared' end def a @a ||= Marshal.load(Marshal.dump(Shares.a)) end end p Shares.a shares = Shares.new shares.a << ", but it's own copy" p Shares.a p shares.a cfp:~ > ruby a.rb "not shared" "not shared" "not shared, but it's own copy" this is nicer, but only works for objects you can marshal - obvisouly. a @ http://codeforpeople.com/ -- we can deny everything, except that we have the possibility of being better. simply reflect on that. h.h. the 14th dalai lama