From: John Carter Date: 2004-11-29T13:59:24+09:00 Subject: Re: What is Ruby for "pimpl"? On Mon, 29 Nov 2004, John Carter wrote: > I trying to imagine a ruby translation of the pimpl idiom. Let me be a bit more explicit about what I'm thinking about. I ran a unit test that failed on a syntax error in another module/class. Looking at the error message I realized that class A used B which used C which used D which under certain error conditions that could never occur while testing A, used E. This left me feeling my program was too coupled. Why did the syntax of a module that I wasn't using block me? In C++ I could have hidden the implementation of E behind a pimpl, and all would have been sweet. So thinking out loud... -------file A.rb------------------------------------------------------ require 'FixMe' class A def foo dostuff() rescue BadThingsHappening => details b = FixMe.new( details, x, y, z) b.make_it_all_better end def bah end end ---------------------------------------------------------------------- If I feed this to Ruby it insists that FixMe must be defined. So if I do.... ---------------------------------------------------------------------- require 'A' class C def initialize a = A.new a.bah end end ---------------------------------------------------------------------- Even though I never invoked foo, as soon as I "require 'A'", I must have FixMe initialized. So how about.... ---------------------------------------------------------------------- class A def A.helper( b_class) @@helper = b_class end def foo dostuff() rescue BadThingsHappening => details b = @@helper.new( details, x, y, z) b.make_it_all_better end def bah end end ---------------------------------------------------------------------- This way I could have -File C.rb--------------------------------------------------------------------- require 'A' class C def initialize a = A.new a.bah end end ---------------------------------------------------------------------- and C can be used without FixMe being defined and another script that did use foo do something like... -File other.rb-------------------------------------------------------- require 'FixMe' require 'A' A.helper( FixMe) a = A.new a.foo ---------------------------------------------------------------------- Or even more self contained... ---------------------------------------------------------------------- class SimpleHelper def initialize(details) @details = details end def make_it_all_better raise "I can't make '#{details}' better, I'm too dumb" end end class A @@helper = SimpleHelper def A.helper( b_class) @@helper = b_class end def foo dostuff() rescue BadThingsHappening => details b = @@helper.new( details, x, y, z) b.make_it_all_better end def bah end end ---------------------------------------------------------------------- But this still requires a concrete definition of a Helper, so a simpler version might be.. ---------------------------------------------------------------------- class A @@helper = nil def A.helper( b_class) @@helper = b_class end def foo dostuff() rescue BadThingsHappening => details raise details unless @@helper b = @@helper.new( details, x, y, z) b.make_it_all_better end def bah end end ---------------------------------------------------------------------- That looks good, and has simplified my tests, but has complicated the client code for A. Sorry for thinking out loud, excuse me for existing. John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@tait.co.nz New Zealand The universe is absolutely plastered with the dashed lines exactly one space long.