From: Robert Klemme Date: 2009-01-26T22:55:30+09:00 Subject: Re: Question about BlankSlate.reveal 2009/1/25 Gregory Brown : > Hi folks, > > I've been working on a chapter for "Ruby Best Practices"[0] about the > dynamic nature of Ruby, and I initially thought Jim Weirich's > BlankSlate would be an excellent example (even though 1.9 has > BasicObject). > However, when I look at the reveal class method, I found what seems to > be a fairly major limitation that I am having a hard time glossing > over in my prose. > > The issue is that when you reveal a previously hidden method, the > UnboundMethod that was stored gets bound to whatever the first > instance is that calls the revealed method, because Jim's code caches > the bound_method via a closure. The best 'fix' I got was to drop the > caching and rebind the method to self on every single method call, but > I wasn't able to get away with that without saying "This is probably a > performance nightmare". Does anyone have a better suggested fix? The > original code for reveal, pulled from the builder gem, is below. From what you write caching a bound method seems a bad idea because it is instance specific. Caching of an unbound method would seem much more reasonable (unless, that is, I am missing something). On the other hand: > [0] http://rubybestpractices.com > > ### Code pulled from blankslate.rb in the builder gem. > > # Redefine a previously hidden method so that it may be called on a blank > # slate object. > def reveal(name) > bound_method = nil > unbound_method = find_hidden_method(name) > fail "Don't know how to reveal method '#{name}'" unless unbound_method > define_method(name) do |*args| > bound_method ||= unbound_method.bind(self) > bound_method.call(*args) > end > end > end I do not really see caching that extends the instance on which #reveal was invoked. There is actually one closure per instance (more correctly: one closure per call of reveal) and so no global cache. Where exactly is your problem? Cheers robert -- remember.guy do |as, often| as.you_can - without end