[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

nested methods don't really exist?!

Artur Merke

6/1/2007 12:37:00 PM

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?

27 Answers

fREW

6/1/2007 6:48:00 PM

0

On 6/1/07, Artur Merke <am@artbot.de> 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

Robert Klemme

6/1/2007 7:42:00 PM

0

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

Nasir Khan

6/1/2007 8:08:00 PM

0

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

- nasir

On 6/1/07, Artur Merke <am@artbot.de> 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?
>
>
>

Brian Candler

6/1/2007 8:35:00 PM

0

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

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

Regards,

Brian.

Trans

6/1/2007 9:14:00 PM

0



On Jun 1, 3:45 pm, Robert Klemme <shortcut...@googlemail.com> 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.


fREW

6/1/2007 9:23:00 PM

0

On 6/1/07, Trans <transfire@gmail.com> wrote:
>
>
> On Jun 1, 3:45 pm, Robert Klemme <shortcut...@googlemail.com> 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

Rick DeNatale

6/1/2007 10:58:00 PM

0

On 6/1/07, Trans <transfire@gmail.com> wrote:
> On Jun 1, 3:45 pm, Robert Klemme <shortcut...@googlemail.com> 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.denh...

dblack

6/2/2007 12:42:00 AM

0

Trans

6/2/2007 5:11:00 AM

0



On Jun 1, 6:57 pm, "Rick DeNatale" <rick.denat...@gmail.com> 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.


Robert Klemme

6/2/2007 8:51:00 AM

0

On 01.06.2007 23:14, Trans wrote:
>
> On Jun 1, 3:45 pm, Robert Klemme <shortcut...@googlemail.com> 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