nested methods good or bad design

Discussion in 'Ruby' started by John Maclean, Jun 30, 2008.

  1. John Maclean

    John Maclean Guest

    =begin
    Hey chaps,

    Is it bad practice to have nested methods? I'm sure that it would
    result in messey/cluttered code. Does any one actually code like that
    at all? Not really -essential- as everything is working, (even better
    than), as expected without nested methods. Just would be nice to know
    what the gurus andmy peers think on this one.

    - jjm
    =end

    class Foo
    def initialize(this, that, the_other)
    @this = this
    ..
    end

    def method_1?
    # here I check for some criteria
    if %x[some_command] == "some criteria"
    @this = true
    end

    # every other method from here on depends on @this == true. Would be nice to be able to skip the remained of the code if @this != true

    def method_2
    # do all of this stuff if @this = true
    end
     
    John Maclean, Jun 30, 2008
    #1
    1. Advertising

  2. John Maclean

    ara.t.howard Guest

    On Jun 30, 2008, at 9:42 AM, John Maclean wrote:

    > def method_1?
    > # here I check for some criteria
    > if %x[some_command] == "some criteria"
    > @this = true
    > end
    >
    > # every other method from here on depends on @this == true. Would
    > be nice to be able to skip the remained of the code if @this != true
    >
    > def method_2
    > # do all of this stuff if @this = true
    > end


    this is *exactly* what closures are for

    def method_1
    method_2 = @this ? lambda{ p 'yup' } : lambda{ p 'nope' }
    method_3 = @this ? lambda{ p 'a' } : lambda{ p 'b' }

    method_2.call
    method_3.call

    regards.

    a @ http://codeforpeople.com/
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
     
    ara.t.howard, Jun 30, 2008
    #2
    1. Advertising

  3. John Maclean wrote:
    > =begin
    > Hey chaps,
    >
    > Is it bad practice to have nested methods? I'm sure that it would
    > result in messey/cluttered code. Does any one actually code like that
    > at all? Not really -essential- as everything is working, (even better
    > than), as expected without nested methods. Just would be nice to know
    > what the gurus andmy peers think on this one.
    >
    > - jjm
    > =end
    >
    > class Foo
    > def initialize(this, that, the_other)
    > @this = this
    > ..
    > end
    >
    > def method_1?
    > # here I check for some criteria
    > if %x[some_command] == "some criteria"
    > @this = true
    > end
    >
    > # every other method from here on depends on @this == true. Would be nice to be able to skip the remained of the code if @this != true
    >
    > def method_2
    > # do all of this stuff if @this = true
    > end


    If you intend to skip defining those other methods, you need a state
    variable (constant, class var, whatever) that has a lifespan longer than
    that of the instances of your class. @this is going to be nil until set
    by method_1?, which can only be called against an instance of Foo, which
    can only happen after Foo has already been defined along with the
    methods in Foo. But you can put such logic in the Foo class object to
    achieve the effect you're looking for:

    class Foo
    class << self
    def method_1?
    # here I check for some criteria
    if %x[some_command] == "some criteria"
    true
    else
    false
    end
    end
    end

    if method_1?
    def method_2
    # etc
    end
    end
    end

    method_2 will only be defined if your criteria is met.

    - Charlie
     
    Charles Oliver Nutter, Jul 1, 2008
    #3
  4. ara.t.howard wrote:
    > this is *exactly* what closures are for
    >
    > def method_1
    > method_2 = @this ? lambda{ p 'yup' } : lambda{ p 'nope' }
    > method_3 = @this ? lambda{ p 'a' } : lambda{ p 'b' }
    >
    > method_2.call
    > method_3.call


    method_2 and method_3 are not long-lived, so if OP intention was to
    conditionally define methods, closures are a rather orthogonal concept.

    - Charlie
     
    Charles Oliver Nutter, Jul 1, 2008
    #4
  5. John Maclean

    Guest

    On Jun 30, 12:42 pm, John Maclean <> wrote:
    > =begin
    > Hey chaps,
    >
    > Is it bad practice to have nested methods? I'm sure that it would
    > result in messey/cluttered code. Does any one actually code like that
    > at all? Not really -essential- as everything is working, (even better
    > than), as expected without nested methods. Just would be nice to know
    > what the gurus andmy peers think on this one.
    >


    I'm not sure I understand completely, but how is having a variable (or
    any other object) laying around representing that the system can call
    method2 is cleaner than:

    def method1
    if criteria
    def method 2
    ##...
    end
    end
    end

    ?

    I find that easier to follow than:

    def method1
    if criteria
    #set some flag
    end
    end

    ##.. more code

    ##check the flag

    def method2
    ##...
    end

    The only way that the first alternative could get messy is with very
    long methods, wich you should avoid anyway.

    Lucas.
     
    , Jul 1, 2008
    #5
  6. John Maclean

    ThoML Guest

    > Is it bad practice to have nested methods?

    Like Eiffel, Smalltalk, Java, Ruby doesn't have nested methods
    unlike ... uhm, Python, Scheme etc. (Everything IIRC and AFAIK which
    doesn't mean much ATM. :)

    Example:

    def a
    def b
    p 1
    end
    b
    end

    a
    => 1
    b
    => 1

    a and b are defined at the same level. This trick can be used to
    dynamically (re)define methods at runtime and can be handy at times.

    You could create a normal method and make that private.
     
    ThoML, Jul 1, 2008
    #6
  7. John Maclean

    Guest

    On Jul 1, 5:17 pm, ThoML <> wrote:

    >
    > def a
    >     def b
    >         p 1
    >     end
    >     b
    > end
    >
    > a
    > => 1
    > b
    > => 1
    >


    But this has the additional (somewhat usefull) effect that calling b
    before a will give an error. Maybe I'm not understanding what you are
    reffering to as nested methods or "same level", what can you do in
    phyton or scheme that behaves different from this?

    Lucas.

    Lucas.
     
    , Jul 1, 2008
    #7
  8. John Maclean

    ThoML Guest

    > Maybe I'm not understanding what you are
    > reffering to as nested methods or "same level", what can you do in
    > phyton or scheme that behaves different from this?


    >>> def a():

    .... def b():
    .... print(1)
    .... b()
    ....
    >>> a()

    1
    >>> b()

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    NameError: name 'b' is not defined

    b() is not accessible from outside of a().
     
    ThoML, Jul 2, 2008
    #8
  9. John Maclean

    ara.t.howard Guest

    On Jul 1, 2008, at 9:47 PM, ThoML wrote:

    > b() is not accessible from outside of a().



    you have to execute it to make the definition occur, after that it is:


    cfp:~ > cat a.rb
    def a
    def b
    42
    end
    end

    p a
    p b



    cfp:~ > ruby a.rb
    nil
    42


    a @ http://codeforpeople.com/
    --
    we can deny everything, except that we have the possibility of being
    better. simply reflect on that.
    h.h. the 14th dalai lama
     
    ara.t.howard, Jul 2, 2008
    #9
  10. John Maclean

    ThoML Guest

    > > b() is not accessible from outside of a().
    >
    > you have to execute it to make the definition occur


    This referred to the Python counter example -- because KA asked how
    Python/Scheme/... are different in this respect.
     
    ThoML, Jul 2, 2008
    #10
  11. John Maclean

    Guest

    On Jul 2, 12:49 am, ThoML <> wrote:
    > > Maybe I'm not understanding what you are
    > > reffering to as nested methods or "same level", what can you do in
    > > phyton or scheme that behaves different from this?
    > >>> def a():

    >
    > ...     def b():
    > ...         print(1)
    > ...     b()
    > ...>>> a()
    > 1
    > >>> b()

    >
    > Traceback (most recent call last):
    >   File "<stdin>", line 1, in <module>
    > NameError: name 'b' is not defined
    >
    > b() is not accessible from outside of a().


    Y get it, it's as if each method defines a namespace, can
    youdosomething like a()::b() from ouside a?

    Lucas.
     
    , Jul 2, 2008
    #11
  12. John Maclean

    ThoML Guest

    > Y get it, it's as if each method defines a namespace, can
    > youdosomething like a()::b() from ouside a?


    I'd say no. You'd probably have to ask this on a python list for more
    details. I don't think this would make much sense though:

    --> def a(x, y):
    .... def b(z):
    .... return z * y
    .... return x * b(4)
    ....
    --> a(2, 3)
    24

    What should a::b(10) return if this were possible?

    BTW I personally like nested functions/methods. This was/is one thing
    I miss in ruby.

    Anyway, I think though the OP asked for something different. The
    problem with that would be that the proposed code IMHO is that the
    definition of a method for all objects of that class would depend on
    the value of an instance variable of one specific object. Ara's
    solution or instance methods would solve this. If I'm not mistaken,
    another approach could be:

    class A
    def a(x)
    if x == 0
    def self.b
    10
    end
    else
    def self.b
    20
    end
    end
    self
    end
    end

    o1 = A.new.a(0)
    o2 = A.new.a(1)
    p o2.b, o1.b
    => [20, 10]
     
    ThoML, Jul 2, 2008
    #12
  13. John Maclean

    Guest

    On Jul 2, 2:00 pm, ThoML <> wrote:
    > > Y get it, it's as if each method defines a namespace, can
    > > youdosomething like a()::b() from ouside a?

    >
    > I'd say no. You'd probably have to ask this on a python list for more
    > details. I don't think this would make much sense though:
    >
    > --> def a(x, y):
    > ...     def b(z):
    > ...         return z * y
    > ...     return x * b(4)
    > ...
    > --> a(2, 3)
    > 24
    >
    > What should a::b(10) return if this were possible?


    I was asking out of mere curiosity, but in any case it should be
    something like a(2,3)::b(4), but it probably doesn't make sense. With
    respect to de OP, I still find it a good practice, including your
    correction about the instance variable.

    Lucas.
     
    , Jul 2, 2008
    #13
  14. John Maclean

    John Maclean Guest

    Um, thanks for all of the replies chaps. Most of it makes sense. In
    essence all I wanted to do was speed things up and so the first method
    checked a server for something.=20

    All of the other methods check an instance variable, (from the
    first method), and progress with more operations given the value of that
    iv.=20

    Some of the methods __are__ long and that's why I asked if it was good
    practice to ask if nested methods are used in the field. Would make
    sense for smaller methods I guess but not for 70+ lines.=20

    Not tried closures yet - just got into profiling, tracing and
    debugging to see how I can speed things up.

    Many thanks for all of your insight. By the way - this Ruby stuff is
    bloody addictive. Not been so excited for a long time, especially when
    stuff "works".=20

    - jjm


    On Thu, 3 Jul 2008 03:22:04
    +0900 "" <> wrote:

    > On Jul 2, 2:00=C2=A0pm, ThoML <> wrote:
    > > > Y get it, it's as if each method defines a namespace, can
    > > > youdosomething like a()::b() from ouside a?

    > >
    > > I'd say no. You'd probably have to ask this on a python list for
    > > more details. I don't think this would make much sense though:
    > >
    > > --> def a(x, y):
    > > ... =C2=A0 =C2=A0 def b(z):
    > > ... =C2=A0 =C2=A0 =C2=A0 =C2=A0 return z * y
    > > ... =C2=A0 =C2=A0 return x * b(4)
    > > ...
    > > --> a(2, 3)
    > > 24
    > >
    > > What should a::b(10) return if this were possible?

    >=20
    > I was asking out of mere curiosity, but in any case it should be
    > something like a(2,3)::b(4), but it probably doesn't make sense. With
    > respect to de OP, I still find it a good practice, including your
    > correction about the instance variable.
    >=20
    > Lucas.
    >=20
     
    John Maclean, Jul 2, 2008
    #14
  15. John Maclean

    ThoML Guest

    > the first method checked a server for something.
    > All of the other methods check an instance variable


    I don't know when you check the server. Maybe something like this
    would be a viable solution (#create could check the server):

    class A
    def self.create(x)
    case x
    when 0
    A1.new(x)
    else
    A2.new(x)
    end
    end

    def initialize(x)
    @x = x
    end
    end

    class A1 < A
    def f
    nil
    end
    end

    class A2 < A
    def f
    20 + @x
    end
    end

    p A.create(0).f
    => nil
    p A.create(1).f
    => 21
     
    ThoML, Jul 3, 2008
    #15
    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. James Harris
    Replies:
    141
    Views:
    2,590
    Chris Smith
    Feb 24, 2007
  2. Arthur J. O'Dwyer
    Replies:
    16
    Views:
    557
    Chris Smith
    Feb 21, 2007
  3. Replies:
    10
    Views:
    1,256
    Big K
    Feb 2, 2005
  4. rantingrick
    Replies:
    44
    Views:
    1,250
    Peter Pearson
    Jul 13, 2010
  5. jhumanski
    Replies:
    15
    Views:
    742
    Rainer Weikusat
    Apr 24, 2012
Loading...

Share This Page