Nested methods don't really exist?!

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?

On 6/1/07, Artur M. [email protected] wrote:

end
def b

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?

What fREW said. Show me a language that actually allows you to do this
and
I’ll show you a language that is the definition of scoping issues.

You’ve defined method #b inside of method #a, so it should only be
callable when in method #a.

Jason

On 01.06.2007 14:36, Artur M. wrote:

end
def b

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

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 Jun 1, 3:45 pm, Robert K. [email protected] wrote:

def a
irb(main):013:0> A.new.c
my first thought was that method/function ‘b’ would be local to

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

On 6/1/07, Trans [email protected] wrote:

methods in ruby:
end
irb(main):019:0> A.new.c
when ‘b’ isn’t a oneliner)
irb(main):004:2> 2
=> 1
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.

On Sat, Jun 02, 2007 at 04:45:20AM +0900, Robert K. 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 :slight_smile:

Regards,

Brian.

Hi –

On Fri, 1 Jun 2007, Artur M. wrote:

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

On 6/1/07, Trans [email protected] wrote:

class A

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/

On 01.06.2007 23:14, Trans wrote:

def a
class A
Is suppose that method ‘a’ (re)defines method ‘b’ every time it is
irb(main):003:2> def b; 1; end
irb(main):010:0> f.b rescue “no”
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

On Jun 1, 6:57 pm, “Rick DeNatale” [email protected] wrote:

       ...
  inner  # raises NoMethodError even when called from outer

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 :wink: 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?

        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.

On 6/2/07, Robert K. [email protected] wrote:

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

On 6/2/07, Trans [email protected] wrote:

On Jun 1, 6:57 pm, “Rick DeNatale” [email protected] wrote:

    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/

On Jun 2, 7:55 am, “Robert D.” [email protected] wrote:

aren’t very useful --being little more than a shortcut for (class <<
current method).

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? :confused:

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.

On 6/2/07, Robert D. [email protected] wrote:

def a
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/

Hi –

On Sat, 2 Jun 2007, Trans wrote:

There are dynamic behavior scenarios such as memoize where it could be
useful than current Ruby nested methods. Actually the current state of
42
Did you overlook David’s post?
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? :confused:

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

David

On Jun 2, 8:05 am, “Rick DeNatale” [email protected] wrote:

class A
end
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.

Hi –

On Sat, 2 Jun 2007, Trans wrote:

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

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

On Jun 2, 8:41 am, [email protected] 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 :wink:

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.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs