From: Assaph Mehr Date: 2005-01-10T08:21:22+09:00 Subject: Re: Ruby design question: lazy construction of object graph containing forward references Here's a (rather naive) implementation of what you specify. Please note the following: - The syntax is a bit kludgy, since you assign using a block. - The order in which you call the dereference is important. See the last bit for an example. - The previous implementation did the dereference on the first call. This version requires explicit dereference. This is the only way I can think of to solve the situation where some of the calls to y.bar need to return the forward reference (a block) and some need to return the value (after dereferencing). One (very ugly) way to solve some of this is with a global reference store. Unfortunately, blocks recieving blocks is still not available in 1.8. Am not sure what the final syntax and format will be in 2.0. Cheers, Assaph ps. sorry for the lack of code formatting. Blame the google groups web interface. __BEGIN_CODE__ class Object def singleton_class class << self; self; end end end module LazyForwardRef def self.extended o o.instance_variable_set '@forward_references', Hash.new end def forward_ref sym, &val_block def val_block.to_s() 'suspended' end if val_block @forward_references[sym] = val_block end def resolve_references @forward_references.each do |sym, val_block| self.singleton_class.send :attr_accessor, sym self.send "#{sym}=", val_block.call end end def method_missing sym, *args if sym.to_s =~ /=$/ val_block = args.first def val_block.to_s() 'suspended' end if val_block @forward_references[sym] = val_block elsif Proc === @forward_references[sym] @forward_references[sym] else 'uninitialized' end end end x = Object.new; x.extend LazyForwardRef x.forward_ref(:foo) p x.foo #=> something for 'uninitialized' y = Object.new; y.extend LazyForwardRef y.forward_ref(:bar) p y.bar #=> something for 'uninitialized' x.forward_ref(:foo) { y.bar } p x.foo #=> something for 'suspended/lazy' y.forward_ref(:bar) { 10 } p y.bar #=> still suspended y.resolve_references p y.bar #=> 10 p x.foo #=> 10 (or still 'suspended/lazy' if 10 is too difficult) x.resolve_references p x.foo #=> 10 puts '--- wrong resolve order ---' x = Object.new; x.extend LazyForwardRef y = Object.new; y.extend LazyForwardRef x.forward_ref(:qux) { y.qux } y.forward_ref(:qux) { 'qux' } x.resolve_references p x.qux y.resolve_references p y.qux p x.qux x.resolve_references p x.qux