From: Dave Thomas Date: 2002-02-24T09:21:26+09:00 Subject: Re: Object/Memory Management "Sean O'Dell" writes: > Well...I come mainly from C++, which doesn't do reference counting, so > perhaps reference counting isn't such a great idea. I don't know...I just > know that being able to call a finalize method *before* the object is one of > the great things about OOP. You can encapsulate activities inside an object > without the outside world knowing everything going on inside, and they can > use it safely. In Ruby, you often use a different idiom. For example: File.open("/etc/passwd") do |f| ... do stuff with f ... end The File.open method ensures that whatever happens, the file is closed at the end of the block. (but I suspect you now that :) > I considered using "yield" to wrap things up (using block_given? to enforce > using blocks, throwing an exception when a block wasn't provided) to ensure > this happens, but that got really messy fast in one of my apps. I had about > 6 objects to create, all of which required special destruction tasks, and > that meant I had 6-level-deep nested block, complete with 6 calls to yield. > The code looks horrible. It's so much cleaner when you can create 6 objects > in succession, and they destruct in reverse order. I could wrap all 6 > objects inside a block with an ensure clause and then call their destructors > explicitly, but that requires that the outside world know about the > destructors, and that ruins the whole idea of encapsulation. How about having a simple "managed object pool". Then you could write # *untested* class ManagedObjectPool def initialize pool = [] end def <<(obj) pool << obj end def run yield ensure pool.each {|obj| obj.tidy} end end mop = ManagedObjectPool.new mop << config_object mop << another_object mop << yet_another mop.run do # ... rest of code end and have the mop invoke each managed object's 'tidy' method. Dave