From: Rick DeNatale Date: 2007-06-02T07:57:54+09:00 Subject: Re: nested methods don't really exist?! On 6/1/07, Trans wrote: > On Jun 1, 3:45 pm, Robert Klemme wrote: > > On 01.06.2007 14:36, Artur Merke wrote: > > > > > > > > > Hi, > > > > > I've just encountered somehow strange (for me) behavior of nested > > > methods in ruby: > > > > > class A > > > def a > > > def b > > > print "bbb" > > > end > > > end > > > > > def c > > > b > > > end > > > end > > > > > irb(main):013:0> A.new.c > > > bbb=> nil > > > > > class A > > > def b > > > print "BBB" > > > end > > > end > > > irb(main):019:0> A.new.c > > > BBB=> nil > > > > > my first thought was that method/function 'b' would be local to > > > method 'a' in class A (like it would be in Pascal). But this is of > > > course not > > > the case, as the above example shows. > > > > > Is suppose that method 'a' (re)defines method 'b' every time it is > > > called, therefore using nested methods doesn't seem to be a > > > good idea in ruby (better readability but much worse performance, esp. > > > when 'b' isn't a oneliner) > > > > > any comments? > > > > You're right on. I think that nested methods are a bad thing to have > > especially since invocation of an instance method has side effects on > > all instances: ... > > > > #b is defined only after #a has been invoked at least once. I cannot > > think of a scenario where you would want this behavior. > > There are dynamic behavior scenarios such as memoize where it could be > used. But such cases are pretty rare. So I agree. Unless inner defs > are local to their outer def, akin to local variables, Trans, you lost me there on several counts. What would it mean for an inner def to be local to an inner def. I get the idea that you mean that, in analogy to local variables we'd see this: class A def outer def inner ... end inner # this should work here as should self.inner # but what about class.new.inner # should inner be an instance or singleton method? another rescue "Oops" method(:inner) end private def another inner # raises NoMethodError even when called from outer end end A.new.inner.call # And should this work? So I think the basic meaning is that the inner method would only live during the execution of the outer method, and would be inaccessible outside of that stack frame, except maybe if they were returned or passed. Of course these all sound like use cases which could easily be handled with a proc and slighly different syntax. > they really aren't very useful --being little more than a shortcut for > (class << self; self; end).define_method(). Of course this wouldn't work since define_method is private. Now as Robert K, points out what really happens is that the inner def is "executed" whenever the outer method is, and other than the timing it does the same thing as if it were in the class/module context. Now if one wanted to avoid re-defining such inner methods, one could write something like: class A def outer unless self.class.instance_methods(false).include?(:inner) def inner "inner: a regular instance method" end end unless singleton_methods(false).include?(:my_inner) def self.my_inner "my_inner: a singleton instance method" end end end end Just anothe way of doing dynamic method definition. Of course you'd need to do something like carefully remove_method'ing those inner methods if you wanted to change them. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/