From: Intransition Date: 2010-08-24T01:19:38+09:00 Subject: Re: Your thoughts on #memo ? On Aug 23, 11:37 am, Robert Klemme wrote: > I could not get that to work on 1.9.1: > > 17:33:49 ~$ irb19 > Ruby version 1.9.1 > irb(main):001:0>  def memo(&block) >    key = eval('__method__', block) >    val = block.call >    singleton_class = (class << self; self; end) >    singleton_class.__send__(:define_method, key){ vairb(main):002:1> l } >    key = eval('__method__', block) > irb(main):003:1>    val = block.call > irb(main):004:1>    singleton_class = (class << self; self; end) > irb(main):005:1>    singleton_class.__send__(:define_method, key){ val } > irb(main):006:1>    val > irb(main):007:1>  end > => nil > irb(main):008:0> class ME > irb(main):009:1> attr_accessor :a > irb(main):010:1> def m;memo { @a }; end > irb(main):011:1> end > => nil > irb(main):012:0> ex=ME.new > => # > irb(main):013:0> ex.a=10 > => 10 > irb(main):014:0> ex.m > TypeError: wrong argument type Proc (expected Binding) >         from (irb):2:in `eval' >         from (irb):2:in `memo' >         from (irb):10:in `m' >         from (irb):14 >         from /opt/bin/irb19:12:in `
' > irb(main):015:0> Looks like you can't pass a Proc to eval in 1.9+. Wonder why that was gotten rid of? Ironically I only leaned one could even do that at all a few month ago! I love having to unlearn. Looks like it can be fixed with: key = eval('__method__', block.binding) > Also I believe the results would not be like your comments suggest > since you redefine the method all the time.  Am I missing something? After the first time, the original method would no longer be accessible (at least not via normal method calling). > > Downside / upsides to the approach? Any suggestions for improvement? > > Or is this just an altogether bad idea? > > I do not see the advantage over plain definition of > > def ex.m; 10; end > > since you are storing a single value anyway.  It seems your approach > is only advantageous if you need to access instance variables because > then it spares some ugly syntax.  But since you have to call #memo > explicitly you can even pass the value to bind to the method as well, > e.g. > >  def memo(name, val) >    (class << self; self; end).define_method(name){ val } >  end > >  ex.memo :a, 10 > > As long as you have to invoke the method setting the value explicitly > you do not gain anything, do you?  Somehow I must be missing something > but I can't see it right now. Yes, part of the reason for this design is to avoid restating the method name. That's the only reason a block is used in fact, to gain access to the callers binding so as to get the method name. The use case for #memo is an alternative to: def m @m ||= .... end But differs in that it avoids the need for an instance variable. I tend to use the "@m ||=" idiom a lot, though I wonder about it's threading implications, and whether something like #memo would be more robust.