nested methods don't really exist?!

Discussion in 'Ruby' started by Artur Merke, Jun 1, 2007.

  1. Artur Merke

    Artur Merke Guest

    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?
    Artur Merke, Jun 1, 2007
    #1
    1. Advertising

  2. Artur Merke

    fREW Guest

    On 6/1/07, 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?
    >
    >
    >


    I am not exactly a wizard, but I think that your issue is context.
    You are trying to call methods that only exist in other methods. This
    should not be! You have to either define it outside of the method and
    then pass it in (or reference it inside) or redefine it. Does that
    help at all?

    --
    -fREW
    fREW, Jun 1, 2007
    #2
    1. Advertising

  3. 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:

    irb(main):001:0> class Foo
    irb(main):002:1> def a
    irb(main):003:2> def b; 1; end
    irb(main):004:2> 2
    irb(main):005:2> end
    irb(main):006:1> end
    => nil
    irb(main):007:0> f=Foo.new
    => #<Foo:0x7ff87288>
    irb(main):008:0> f.b rescue "no"
    => "no"
    irb(main):009:0> f.a
    => 2
    irb(main):010:0> f.b rescue "no"
    => 1
    irb(main):011:0>
    irb(main):012:0* Foo.new.b rescue "no"
    => 1
    irb(main):013:0>

    #b is defined only after #a has been invoked at least once. I cannot
    think of a scenario where you would want this behavior.

    Kind regards

    robert
    Robert Klemme, Jun 1, 2007
    #3
  4. Artur Merke

    Nasir Khan Guest

    Yes this would re-define the method b() on each invocation of a() at
    the class level.
    Depending upon what you actually want, there may be different options
    in Ruby, but you can use this "redefinition" nicely if you create a
    singleton method of the same name as the enclosing method to get
    interesting possibilities. (which is not exactly re-definition btw...)

    One such use case is discussed on my blog -
    http://codepresso.blogspot.com/2007/03/calculate-once-cache-forever.html

    - nasir

    On 6/1/07, 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?
    >
    >
    >
    Nasir Khan, Jun 1, 2007
    #4
  5. On Sat, Jun 02, 2007 at 04:45:20AM +0900, Robert Klemme wrote:
    > 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:


    FWIW, nested subs in Perl cause horrendous problems. For the gory details,
    see http://perl.apache.org/docs/general...l#my____Scoped_Variable_in_Nested_Subroutines

    This should be enough to put you off mod_perl for life :)

    Regards,

    Brian.
    Brian Candler, Jun 1, 2007
    #5
  6. Artur Merke

    Trans Guest

    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:
    >
    > irb(main):001:0> class Foo
    > irb(main):002:1> def a
    > irb(main):003:2> def b; 1; end
    > irb(main):004:2> 2
    > irb(main):005:2> end
    > irb(main):006:1> end
    > => nil
    > irb(main):007:0> f=Foo.new
    > => #<Foo:0x7ff87288>
    > irb(main):008:0> f.b rescue "no"
    > => "no"
    > irb(main):009:0> f.a
    > => 2
    > irb(main):010:0> f.b rescue "no"
    > => 1
    > irb(main):011:0>
    > irb(main):012:0* Foo.new.b rescue "no"
    > => 1
    > irb(main):013:0>
    >
    > #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, they really
    aren't very useful --being little more than a shortcut for (class <<
    self; self; end).define_method().

    T.
    Trans, Jun 1, 2007
    #6
  7. Artur Merke

    fREW Guest

    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:
    > >
    > > irb(main):001:0> class Foo
    > > irb(main):002:1> def a
    > > irb(main):003:2> def b; 1; end
    > > irb(main):004:2> 2
    > > irb(main):005:2> end
    > > irb(main):006:1> end
    > > => nil
    > > irb(main):007:0> f=Foo.new
    > > => #<Foo:0x7ff87288>
    > > irb(main):008:0> f.b rescue "no"
    > > => "no"
    > > irb(main):009:0> f.a
    > > => 2
    > > irb(main):010:0> f.b rescue "no"
    > > => 1
    > > irb(main):011:0>
    > > irb(main):012:0* Foo.new.b rescue "no"
    > > => 1
    > > irb(main):013:0>
    > >
    > > #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, they really
    > aren't very useful --being little more than a shortcut for (class <<
    > self; self; end).define_method().
    >
    > T.
    >
    >
    >


    Once for a class I had to write a simple regular expression parser and
    I used some inner methods (w/closures) and it turned out to make the
    code a lot more simple. If you have to pass a variable to every
    method in a class, it might as well be a global. Similarly, if it's
    used in every inner method in a large method, you might as well use
    closures.

    In general it is probably overkill to have inner methods, but with
    complex code I found it pretty convenient.

    --
    -fREW
    fREW, Jun 1, 2007
    #7
  8. 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/
    Rick DeNatale, Jun 1, 2007
    #8
  9. Artur Merke

    Guest

    Hi --

    On Fri, 1 Jun 2007, 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


    I get:

    inner.rb:9:in `c': undefined local variable or method `b' for
    #<A:0x1ea244> (NameError) from inner.rb:13

    with Ruby 1.8.6, because b doesn't get defined until a is called.

    Can you reproduce exactly what you're doing, including Ruby version?


    David

    --
    Q. What is THE Ruby book for Rails developers?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
    , Jun 2, 2007
    #9
  10. Artur Merke

    Trans Guest

    On Jun 1, 6:57 pm, "Rick DeNatale" <> wrote:

    > 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.


    Right. Inner def would be treated just like local variables. There
    would be no instance access, private or public. They would be very
    much like procs. But procs differ in a couple of ways, most notably in
    that they have a different call syntax. With local methods one could
    do:

    class X
    def a
    "foo"
    end
    def b
    def a
    "bar"
    end
    a
    end
    end

    X.new.b => "bar"

    The point being that the local method can serve in place of the
    instance methods without subsequent syntax changes to the call --
    something lambdas don't allow (ie. the call to #a would have to be
    changed to a.call or a[] instead).

    > > 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.


    Common mistake on my part. Making #define_method public is not beyond
    me ;) But I am wrong about the shortcut. I thought the inner defs were
    creating singleton methods. I'm a bit startled to see they are
    defining instance methods, and pinned to the module/class in which the
    outer method is defined --not self.class. (Try it with a module to see
    what I mean.) Inner defs are a rather new feature AFAIK, I wonder how
    that decision was arrived at? Is there some reason for this, or is it
    just a stop gag measure toward the eventual behavior in Ruby 2.0?

    > 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


    Could. Though the would not work if the method were defined in an
    included module.

    T.
    Trans, Jun 2, 2007
    #10
  11. On 01.06.2007 23:14, 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:
    >>
    >> irb(main):001:0> class Foo
    >> irb(main):002:1> def a
    >> irb(main):003:2> def b; 1; end
    >> irb(main):004:2> 2
    >> irb(main):005:2> end
    >> irb(main):006:1> end
    >> => nil
    >> irb(main):007:0> f=Foo.new
    >> => #<Foo:0x7ff87288>
    >> irb(main):008:0> f.b rescue "no"
    >> => "no"
    >> irb(main):009:0> f.a
    >> => 2
    >> irb(main):010:0> f.b rescue "no"
    >> => 1
    >> irb(main):011:0>
    >> irb(main):012:0* Foo.new.b rescue "no"
    >> => 1
    >> irb(main):013:0>
    >>
    >> #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, they really
    > aren't very useful --being little more than a shortcut for (class <<
    > self; self; end).define_method().


    That's exactly what they are not. If at all they are a shortcut for
    self.class.define_method(), i.e. methods defined that way a regular
    instance methods.

    I also think that for memoize and such other mechanisms are far more
    useful than current Ruby nested methods. Actually the current state of
    affairs is a queer mix, because the definition is nested but the scope
    is not (they are neither restricted to the current instance nor to the
    current method). Maybe that is the major reason for them not being too
    useful.

    Kind regards

    robert
    Robert Klemme, Jun 2, 2007
    #11
  12. Artur Merke

    Robert Dober Guest

    On 6/2/07, Robert Klemme <> wrote:

    > >> #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, they really
    > > aren't very useful --being little more than a shortcut for (class <<
    > > self; self; end).define_method().

    >
    > That's exactly what they are not. If at all they are a shortcut for
    > self.class.define_method(), i.e. methods defined that way a regular
    > instance methods.
    >
    > I also think that for memoize and such other mechanisms are far more
    > useful than current Ruby nested methods. Actually the current state of
    > affairs is a queer mix, because the definition is nested but the scope
    > is not (they are neither restricted to the current instance nor to the
    > current method).


    Robert I think they are:
    # vim: sts=2 sw=2 expandtab nu tw=0:

    class A
    def a
    def b
    42
    end
    end

    end

    p A.new.methods.grep(/^b$/)
    A.new.b
    []
    nested.rb:13: undefined method `b' for #<A:0xb7e337a0> (NoMethodError)

    Did you overlook David's post?
    I get exactly the same behavior than he does on a 1.8.5 Zenwalk
    I have the impression that OP got the victim of a "leftover" in his irb session.

    Cheers
    Robert

    Maybe that is the major reason for them not being too
    > useful.
    >
    > Kind regards
    >
    > robert
    >
    >



    --
    You see things; and you say Why?
    But I dream things that never were; and I say Why not?
    -- George Bernard Shaw
    Robert Dober, Jun 2, 2007
    #12
  13. On 6/2/07, Trans <> wrote:
    >
    >
    > On Jun 1, 6:57 pm, "Rick DeNatale" <> wrote:


    > > 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

    >
    > Could. Though the would not work if the method were defined in an
    > included module.


    It was a conscious choice on my part to using instance_methods(false)
    for the instance method. This allows overriding with a new method, but
    not redefining it the second time. If you wanted to not override then
    you could use just instance_methods with the default true parameter
    which returns methods from superclasses and included modules also.

    It's a matter of what you are trying to do. There are other techniques
    for determining the current state, like using defined?, with different
    variations and edge cases.
    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
    Rick DeNatale, Jun 2, 2007
    #13
  14. On 6/2/07, Robert Dober <> wrote:
    > On 6/2/07, Robert Klemme <> wrote:
    >Actually the current state of
    > > affairs is a queer mix, because the definition is nested but the scope
    > > is not (they are neither restricted to the current instance nor to the
    > > current method).

    >
    > Robert I think they are:
    > # vim: sts=2 sw=2 expandtab nu tw=0:
    >
    > class A
    > def a
    > def b
    > 42
    > end
    > end
    >
    > end
    >
    > p A.new.methods.grep(/^b$/)
    > A.new.b
    > []
    > nested.rb:13: undefined method `b' for #<A:0xb7e337a0> (NoMethodError)
    >
    > Did you overlook David's post?
    > I get exactly the same behavior than he does on a 1.8.5 Zenwalk
    > I have the impression that OP got the victim of a "leftover" in his irb
    > session.


    Perhaps the OP was, but I think that Robert's statements are still correct:

    $ cat innerdef.rb
    class A
    def a
    def b
    42
    end
    end
    end

    puts "Using #{RUBY_VERSION}"
    a = A.new
    puts "Before invocation of a"
    p a.methods & %w{a b}
    p A.instance_methods(false)
    a.a
    puts "After invocation of a"
    p a.methods & %w{a b}
    p A.new.methods & %w{a b}
    p A.instance_methods(false)

    $ ruby innerdef.rb
    Using 1.8.5
    Before invocation of a
    ["a"]
    ["a"]
    After invocation of a
    ["a", "b"]
    ["a", "b"]
    ["a", "b"]


    --
    Rick DeNatale

    My blog on Ruby
    http://talklikeaduck.denhaven2.com/
    Rick DeNatale, Jun 2, 2007
    #14
  15. Artur Merke

    Trans Guest

    On Jun 2, 7:55 am, "Robert Dober" <> wrote:
    > On 6/2/07, Robert Klemme <> wrote:
    >
    >
    >
    > > >> #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, they really
    > > > aren't very useful --being little more than a shortcut for (class <<
    > > > self; self; end).define_method().

    >
    > > That's exactly what they are not. If at all they are a shortcut for
    > > self.class.define_method(), i.e. methods defined that way a regular
    > > instance methods.

    >
    > > I also think that for memoize and such other mechanisms are far more
    > > useful than current Ruby nested methods. Actually the current state of
    > > affairs is a queer mix, because the definition is nested but the scope
    > > is not (they are neither restricted to the current instance nor to the
    > > current method).

    >
    > Robert I think they are:
    > # vim: sts=2 sw=2 expandtab nu tw=0:
    >
    > class A
    > def a
    > def b
    > 42
    > end
    > end
    >
    > end
    >
    > p A.new.methods.grep(/^b$/)
    > A.new.b
    > []
    > nested.rb:13: undefined method `b' for #<A:0xb7e337a0> (NoMethodError)
    >
    > Did you overlook David's post?
    > I get exactly the same behavior than he does on a 1.8.5 Zenwalk
    > I have the impression that OP got the victim of a "leftover" in his irb session.
    >
    > Cheers
    > Robert
    >
    > Maybe that is the major reason for them not being too
    >
    > > useful.

    >
    > > Kind regards

    >
    > > robert



    Ah, so inner defs won't be allowed after all. Figures, I guess. Why
    have useful syntax when you can throw an error? :/

    To be honest, I'm not sure I understand Ruby's vision for the future
    these days. Why isn't Ruby further embracing the dynamic revolution
    it's helped ignite? For example, why aren't we seeing 'def' become a
    method, just like 'new' already is? I guess maybe the innovation is
    over and Matz is settling into performance matters only.

    T.
    Trans, Jun 2, 2007
    #15
  16. Artur Merke

    Guest

    Hi --

    On Sat, 2 Jun 2007, Trans wrote:

    >
    >
    > On Jun 2, 7:55 am, "Robert Dober" <> wrote:
    >> On 6/2/07, Robert Klemme <> wrote:
    >>
    >>
    >>
    >>>>> #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, they really
    >>>> aren't very useful --being little more than a shortcut for (class <<
    >>>> self; self; end).define_method().

    >>
    >>> That's exactly what they are not. If at all they are a shortcut for
    >>> self.class.define_method(), i.e. methods defined that way a regular
    >>> instance methods.

    >>
    >>> I also think that for memoize and such other mechanisms are far more
    >>> useful than current Ruby nested methods. Actually the current state of
    >>> affairs is a queer mix, because the definition is nested but the scope
    >>> is not (they are neither restricted to the current instance nor to the
    >>> current method).

    >>
    >> Robert I think they are:
    >> # vim: sts=2 sw=2 expandtab nu tw=0:
    >>
    >> class A
    >> def a
    >> def b
    >> 42
    >> end
    >> end
    >>
    >> end
    >>
    >> p A.new.methods.grep(/^b$/)
    >> A.new.b
    >> []
    >> nested.rb:13: undefined method `b' for #<A:0xb7e337a0> (NoMethodError)
    >>
    >> Did you overlook David's post?
    >> I get exactly the same behavior than he does on a 1.8.5 Zenwalk
    >> I have the impression that OP got the victim of a "leftover" in his irb session.
    >>
    >> Cheers
    >> Robert
    >>
    >> Maybe that is the major reason for them not being too
    >>
    >>> useful.

    >>
    >>> Kind regards

    >>
    >>> robert

    >
    >
    > Ah, so inner defs won't be allowed after all. Figures, I guess. Why
    > have useful syntax when you can throw an error? :/


    They're allowed; they're just not executed until the enclosing method
    is executed.


    David

    --
    Q. What is THE Ruby book for Rails developers?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
    , Jun 2, 2007
    #16
  17. Artur Merke

    Trans Guest

    On Jun 2, 8:05 am, "Rick DeNatale" <> wrote:
    > On 6/2/07, Trans <> wrote:
    >
    >
    >
    >
    >
    > > On Jun 1, 6:57 pm, "Rick DeNatale" <> wrote:
    > > > 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

    >
    > > Could. Though the would not work if the method were defined in an
    > > included module.

    >
    > It was a conscious choice on my part to using instance_methods(false)
    > for the instance method. This allows overriding with a new method, but
    > not redefining it the second time. If you wanted to not override then
    > you could use just instance_methods with the default true parameter
    > which returns methods from superclasses and included modules also.
    >
    > It's a matter of what you are trying to do. There are other techniques
    > for determining the current state, like using defined?, with different
    > variations and edge cases.



    Oh, I wasn't saying anything about your code. It's fine. I was just
    further pointing out the slightly odd behavior that one might not
    expect (I know I didn't), when using a module instead of a class.
    Here's an example:

    module N
    def a
    def b
    "foo"
    end
    end
    end

    class X
    include N
    end

    X.new.a

    N.instance_methods(false) #=> ["a", "b"]

    Notice #b isn't defined in X.

    T.
    Trans, Jun 2, 2007
    #17
  18. Artur Merke

    Trans Guest

    On Jun 2, 8:41 am, wrote:
    > Hi --
    > They're allowed; they're just not executed until the enclosing method
    > is executed.


    Okay. I misunderstood (should have read your post more carefully...
    actually I should have gotten my coffee first ;)

    So can anyone explain to me why this behavior was chosen over the
    other possibilities? Namely

    1) Why are they defined in the outer defs namespace and not
    self.class.
    2) Why is this better then localizing the definition to the outer
    method?

    I tend to favor localization. But really that's only b/c lamdas can't
    be called the same way methods can, so they can't be used as local
    drop in replacements. This is one of great things about ruby's
    "ambiguity" between local vars and methods. Eg.

    class X
    def f; 10; end
    def g
    f = 20 # local override
    f
    end
    end

    Unfortunately we have no simple way to do this using lamdas, which
    would make this much more useful.

    T.


    > David
    >
    > --
    > Q. What is THE Ruby book for Rails developers?
    > A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    > (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
    > Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    > A. Ruby Power and Light, LLC (http://www.rubypal.com)
    Trans, Jun 2, 2007
    #18
  19. Artur Merke

    Guest

    Hi --

    On Sat, 2 Jun 2007, Trans wrote:

    >
    >
    > On Jun 2, 8:41 am, wrote:
    >> Hi --
    >> They're allowed; they're just not executed until the enclosing method
    >> is executed.

    >
    > Okay. I misunderstood (should have read your post more carefully...
    > actually I should have gotten my coffee first ;)
    >
    > So can anyone explain to me why this behavior was chosen over the
    > other possibilities? Namely
    >
    > 1) Why are they defined in the outer defs namespace and not
    > self.class.


    I would guess because it's easier to constrain it to self.class, than
    to un-constrain it to the outer class. In other words, you can do:

    def a
    def c
    end
    def self.b
    end
    end

    but if the def c implied self, you'd have to jump through more hoops
    to get at the outer class than you do to get *from* the outer class to
    the singleton class. (I'm not claiming any great usefulness for this
    idiom, but I imagine that's why the syntax is optimized for the outer
    class case.)

    > 2) Why is this better then localizing the definition to the outer
    > method?
    >
    > I tend to favor localization. But really that's only b/c lamdas can't
    > be called the same way methods can, so they can't be used as local
    > drop in replacements. This is one of great things about ruby's
    > "ambiguity" between local vars and methods. Eg.
    >
    > class X
    > def f; 10; end
    > def g
    > f = 20 # local override
    > f
    > end
    > end
    >
    > Unfortunately we have no simple way to do this using lamdas, which
    > would make this much more useful.


    I'm not sure what it would mean to localize the method. Do you mean
    it would be automatically removed from the class (whether singleton or
    otherwise) when the method returns? That seems like something more
    suited to an anonymous function. To have volatile method names like
    that would also be a threading nightmare, I suspect.


    David

    --
    Q. What is THE Ruby book for Rails developers?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
    , Jun 2, 2007
    #19
  20. Artur Merke

    Robert Dober Guest

    On 6/2/07, Rick DeNatale <> wrote:
    > On 6/2/07, Robert Dober <> wrote:
    > > On 6/2/07, Robert Klemme <> wrote:
    > >Actually the current state of
    > > > affairs is a queer mix, because the definition is nested but the scope
    > > > is not (they are neither restricted to the current instance nor to the
    > > > current method).

    > >
    > > Robert I think they are:
    > > # vim: sts=2 sw=2 expandtab nu tw=0:
    > >
    > > class A
    > > def a
    > > def b
    > > 42
    > > end
    > > end
    > >
    > > end
    > >
    > > p A.new.methods.grep(/^b$/)
    > > A.new.b
    > > []
    > > nested.rb:13: undefined method `b' for #<A:0xb7e337a0> (NoMethodError)
    > >
    > > Did you overlook David's post?
    > > I get exactly the same behavior than he does on a 1.8.5 Zenwalk
    > > I have the impression that OP got the victim of a "leftover" in his irb
    > > session.

    >
    > Perhaps the OP was, but I think that Robert's statements are still correct:

    Sure was, sure was, I am just with you right now, thanks to your
    explanation Rick.
    I mean Robert's as emphasized by Rick, just gotta reread the whole
    thread, now that I know what you are talking about :(

    Thx a lot to both of you.

    Robert
    --
    You see things; and you say Why?
    But I dream things that never were; and I say Why not?
    -- George Bernard Shaw
    Robert Dober, Jun 2, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Y.S.
    Replies:
    3
    Views:
    975
    strajan
    Sep 17, 2003
  2. LT
    Replies:
    7
    Views:
    2,071
    Phlip
    Jul 25, 2004
  3. Petr Prikryl

    Does -U option really exist?

    Petr Prikryl, Mar 10, 2006, in forum: Python
    Replies:
    0
    Views:
    236
    Petr Prikryl
    Mar 10, 2006
  4. jalkadir
    Replies:
    2
    Views:
    360
  5. Markus Mohr
    Replies:
    7
    Views:
    226
    Thomas 'PointedEars' Lahn
    Nov 28, 2003
Loading...

Share This Page