Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

nested methods don't really exist?!

3 views
Skip to first unread message

Artur Merke

unread,
Jun 1, 2007, 8:36:34 AM6/1/07
to
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?

fREW

unread,
Jun 1, 2007, 2:48:19 PM6/1/07
to

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

Robert Klemme

unread,
Jun 1, 2007, 3:41:55 PM6/1/07
to

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

Nasir Khan

unread,
Jun 1, 2007, 4:08:15 PM6/1/07
to
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 <a...@artbot.de> wrote:

Brian Candler

unread,
Jun 1, 2007, 4:34:57 PM6/1/07
to
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/perl_reference/perl_reference.html#my____Scoped_Variable_in_Nested_Subroutines

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

Regards,

Brian.

Trans

unread,
Jun 1, 2007, 5:14:10 PM6/1/07
to

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.


fREW

unread,
Jun 1, 2007, 5:23:27 PM6/1/07
to

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

Rick DeNatale

unread,
Jun 1, 2007, 6:57:54 PM6/1/07
to
On 6/1/07, Trans <tran...@gmail.com> 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,

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/

dbl...@wobblini.net

unread,
Jun 1, 2007, 8:42:13 PM6/1/07
to
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)

Trans

unread,
Jun 2, 2007, 1:11:14 AM6/2/07
to

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.


Robert Klemme

unread,
Jun 2, 2007, 4:51:09 AM6/2/07
to

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 Dober

unread,
Jun 2, 2007, 7:55:59 AM6/2/07
to
On 6/2/07, Robert Klemme <short...@googlemail.com> 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

Rick DeNatale

unread,
Jun 2, 2007, 8:05:26 AM6/2/07
to

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

unread,
Jun 2, 2007, 8:23:18 AM6/2/07
to
On 6/2/07, Robert Dober <robert...@gmail.com> wrote:
> On 6/2/07, Robert Klemme <short...@googlemail.com> 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"]

Trans

unread,
Jun 2, 2007, 8:34:44 AM6/2/07
to

On Jun 2, 7:55 am, "Robert Dober" <robert.do...@gmail.com> wrote:


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.


dbl...@wobblini.net

unread,
Jun 2, 2007, 8:41:16 AM6/2/07
to
Hi --

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

Trans

unread,
Jun 2, 2007, 8:58:32 AM6/2/07
to

On Jun 2, 8:05 am, "Rick DeNatale" <rick.denat...@gmail.com> wrote:


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

unread,
Jun 2, 2007, 9:22:09 AM6/2/07
to

On Jun 2, 8:41 am, dbl...@wobblini.net 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.

dbl...@wobblini.net

unread,
Jun 2, 2007, 9:36:09 AM6/2/07
to
Hi --

On Sat, 2 Jun 2007, Trans wrote:

>
>
> On Jun 2, 8:41 am, dbl...@wobblini.net 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.

Robert Dober

unread,
Jun 2, 2007, 10:41:42 AM6/2/07
to
On 6/2/07, Rick DeNatale <rick.d...@gmail.com> wrote:
> On 6/2/07, Robert Dober <robert...@gmail.com> wrote:
> > On 6/2/07, Robert Klemme <short...@googlemail.com> 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

Trans

unread,
Jun 2, 2007, 11:47:49 AM6/2/07
to

Hmm... still a little confusion here. I don;t mean that it would imply
self, but that it would it would imply self.class. In other words, say
we had this code:

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

class X
include N
end

X.new.a

Currently we get:

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

X.instance_methods(false) #=> []

But why isn't it:

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

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

Oh no. I mean that the method would actually be defined essentially
like a local variable is. So I don't think there wouldn't be threading
issues because the method isn't accessible outside it's locality
(outer method). You are right though, anonymous function are more
suited. But the problem there is we loose the method/variable
"ambiguity" I mentioned, because we have to invoke lambdas with a
different syntax.

Hmm.. if we could just methodize variables somehow. Maybe we could use
a different defining method? Say, #fn. Eg.

def x
f = fn { |z| z + 1 }
f(2)
end

x #=> 3

This is interesting because we could apply it to other type of
variables too, such as globals.

$int = fn { |n| Integer(n) }
$int("20") #=> 20

And it would make my argument in favor of localizing inner defs moot.

T.


Trans

unread,
Jun 2, 2007, 12:10:17 PM6/2/07
to

On Jun 2, 11:47 am, Trans <transf...@gmail.com> wrote:

> Oh no. I mean that the method would actually be defined essentially
> like a local variable is. So I don't think there wouldn't be threading
> issues because the method isn't accessible outside it's locality
> (outer method).

s/wouldn't/would/

T.

James Britt

unread,
Jun 2, 2007, 12:18:25 PM6/2/07
to
Trans wrote:

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


Early on, SICP shows the use of inner methods for abstracting function
behavior but Ruby does not afford the same scoping.


--
James Britt

"Simplicity of the language is not what matters, but
simplicity of use."
- Richard A. O'Keefe in squeak-dev mailing list

dbl...@wobblini.net

unread,
Jun 2, 2007, 4:36:36 PM6/2/07
to
Hi --

Yes, I think I misunderstood, and garbled the answer anyway. So let's
start again :-)

> module N
> def a
> def b
> "foo"
> end
> end
> end
>
> class X
> include N
> end
>
> X.new.a
>
> Currently we get:
>
> N.instance_methods(false) #=> ["a", "b"]
> X.instance_methods(false) #=> []
>
> But why isn't it:
>
> N.instance_methods(false) #=> ["a"]
> X.instance_methods(false) #=> ["b"]

I'll give a modified version of my original answer. If the default is
to put the inner def in the same context as the outer def, then the
simplest case (no change in context) has the simplest syntax, and it
goes from there. If the default is to put it in the context of
self.class at the time of execution, then getting it into the flat
context would require more effort.

So I think it just keeps the semantics congruent with the syntax, or
something. One case or the other is going to require class_eval or
equivalent, so I guess having the default case be the one where
there's no automatic context-switching just keeps it more simple.

Robert Dober

unread,
Jun 2, 2007, 4:42:03 PM6/2/07
to

This seems however to be the first case I ever have seen where the
Proxy of the Mixin is not transparent any more.

Robert


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

dbl...@wobblini.net

unread,
Jun 2, 2007, 4:52:46 PM6/2/07
to
Hi --

On Sun, 3 Jun 2007, Robert Dober wrote:

How about constants:

module M
A = 1
def a
puts A
end
end

class C
include M
A = 2
end

C.new.a # 1

I think def is considered to be part of the business of the module
where it's physically located, kind of in a constant way.

Robert Dober

unread,
Jun 2, 2007, 5:55:24 PM6/2/07
to
Ah thanks, I was not aware of this case.

Robert


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

unread,
Jun 2, 2007, 7:07:33 PM6/2/07
to

In other words, the conciser syntax does the thing that would be
harder to do via normal meta-coding. Good enough reason for me.
(Though I'd still like a way to create local methods via anonymous
functions).

Thanks David,
T.


0 new messages