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
=> #<ME:0x10049a74>
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 `<main>'
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.
···
On Aug 23, 11:37 am, Robert Klemme <shortcut...@googlemail.com> wrote: