From: Charles Oliver Nutter Date: 2010-04-07T13:11:15+09:00 Subject: [ruby-core:29290] Re: Proposal: Module#thunk_method On Tue, Apr 6, 2010 at 9:53 PM, Joshua Ballanco wrote: > I've just never seen this pattern in the wild. Perhaps you have an example? Here's a few cases from Rails, in utility libraries used throughout the rest of Rails (and in use applications, I'm sure: http://github.com/rails/rails/blob/master/activesupport/lib/active_support/callbacks.rb#L297 http://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/class/attribute.rb#L50 http://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/class/attribute.rb#L57 http://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb#L30 Here's a concrete example that's perhaps not the best example: http://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L1006 Others may be able to point out some I've missed. For me, I've wanted this as a way to have something faster than an attr accessor that could be lazily defined (or redefined) and not incur overhead of define_method, existence checks like ||=, or class variable searches. > For the moment, I'll give you the benefit of the doubt that this pattern is used. My question, then, would be why is there a need for a new method? Why not just allow define_method to take an optional value argument in place of the block, and take the fast-path in this case? define_method can take an argument in place of the block, but it expects it to be a Proc or Method and raises an error if it is not. If this form were reused for memo_method, it would be impossible to memoize a Proc or Method itself, since define_method would try to use that Proc or Method value as the *body* of the method. So at least the simple define_method(:blah, value) form is out for backward-compat reasons. > Honestly, it seems like this is something that could potentially be optimized away by the implementation without the need for an additional core method. I don't know how to do that, given that define_method always needs either a Proc, block, or Method, and in each case has more dispatch overhead than either a memoized method or even a normal method. None of the implementers have succeeded in making define_method be as fast as a regular Ruby method, much less approaching the performance of attr_access or a native core method that just returns a value. If you have a way to fix this, I'd love to hear it :) It might be possible to inspect the contents of the define_method block, see that it's always returning a given value, and optimize the rest away. You may have to also inspect the surrounding scope to see that it has not escaped and that any variables referenced will never be updated again. There are probably ways to do it, but they're all rather sticky. memo_method would be a handful of lines of code in any implementation and could be finished and working very quickly. - Charlie