Class inside a Method Body

Discussion in 'Ruby' started by Mike Stephens, Nov 17, 2009.

  1. I have a class that works fine if I declare it outside of anything. If
    however I put the code inside a method, Ruby seems to object with a
    message "class definition in method body". Can you suggest why Ruby has
    this constraint?
    --
    Posted via http://www.ruby-forum.com/.
    Mike Stephens, Nov 17, 2009
    #1
    1. Advertising

  2. The class wouldn't be defined until the method is executed, and would be
    re-opened each time the method is executed.

    That's almost certainly not what you want (*). If you want a private
    helper class, I suggest you do it like this:

    class MyClass
    class MyHelper
    ...
    end
    def my_method
    MyHelper.new(...)
    end
    end

    Regards,

    Brian.

    (*) And if you really do, then you can use:

    k = Class.new
    or
    k = Class.new(superclass)
    or use 'eval' to define your class.
    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, Nov 17, 2009
    #2
    1. Advertising

  3. Brian

    Thanks for confirming it is a language feature. I was actually using the
    method as a kind of procedure - I just wanted this bit of the whole
    program to run. In that kind of procedural view of the world it does
    make absolute sense for a class to be declared whenever the procedure
    is called.

    I think this is part of a difficulty I have with Ruby - it seems to want
    to interpret everything in a program, and all the programs called
    (required), before it starts executing anything.
    --
    Posted via http://www.ruby-forum.com/.
    Mike Stephens, Nov 17, 2009
    #3
  4. Hi --

    On Tue, 17 Nov 2009, Mike Stephens wrote:

    > Brian
    >
    > Thanks for confirming it is a language feature. I was actually using the
    > method as a kind of procedure - I just wanted this bit of the whole
    > program to run. In that kind of procedural view of the world it does
    > make absolute sense for a class to be declared whenever the procedure
    > is called.
    >
    > I think this is part of a difficulty I have with Ruby - it seems to want
    > to interpret everything in a program, and all the programs called
    > (required), before it starts executing anything.


    It's more like execution and interpretation are, in effect the same
    process -- so, for example:

    class C
    puts "hi!"
    def x
    puts "x"
    end
    puts "bye!"
    end

    the code is executed as it's encountered, and you get output before
    and after the execution of the method definition. (Of course the
    method body isn't executed until there's an object to which to send
    the "x" method.)


    David

    --
    THE COMPLEAT RUBYIST, Ruby training with Black/Brown/McAnally!
    January 22-23, Tampa, Florica
    Info and registration at http://www.thecompleatrubyist.com
    --------------------------------------
    My new job: http://tinyurl.com/yfpn9hz
    David A. Black, Nov 17, 2009
    #4
  5. David A. Black wrote:
    > the code is executed as it's encountered, and you get output before
    > and after the execution of the method definition. (Of course the
    > method body isn't executed until there's an object to which to send
    > the "x" method.)


    Except: when reading in a source file there is an initial parsing step
    to build the syntax tree, and if that fails then you get a parse error
    and nothing is executed. Mismatched 'end' statements will do that, for
    example.

    The difference between parsing and execution is most important when
    considering local variables.

    def x
    puts "In method x"
    99
    end

    def meth1
    x # << (A)
    end

    def meth2
    x = 123
    x # << (B)
    end

    def meth3
    if false
    x = 456
    end
    x # << (C)
    end

    puts "meth1 returns #{meth1.inspect}"
    puts "meth2 returns #{meth2.inspect}"
    puts "meth3 returns #{meth3.inspect}"

    The decision as to whether x is a local variable or a method call is
    made statically at *parse* time, before anything is executed. This is
    why at point (C), x is determined to a local variable: there was an
    assignment to x earlier in the method. However at run time that line is
    never actually run so its value is nil.
    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, Nov 17, 2009
    #5
  6. 2009/11/17 Mike Stephens <>:
    > Thanks for confirming it is a language feature. I was actually using the
    > method as a kind of procedure - I just wanted this bit of the whole
    > program to run. In that kind of procedural view of the world it does
    > make absolute sense for a class to be =A0declared whenever the procedure
    > is called.


    Can you describe under which circumstances you believe this makes
    sense? After all since the class definition would not change you
    would get the same class definition over and over again. To me that
    does not sound useful.

    If you want to make sure the class is only created when the method is
    executed, you could put it in a separate file which you require in
    that method. Alternatively you can use autoload.

    > I think this is part of a difficulty I have with Ruby - it seems to want
    > to interpret everything in a program, and all the programs called
    > (required), before it starts executing anything.


    If you have a difficulty here I can see two possible explanations: 1.
    there is an issue with Ruby's object model, 2. you are not using the
    language properly. While I don't want to exclude option 1, I tend to
    believe option 2 is more likely. :)

    Kind regards

    robert

    --=20
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
    Robert Klemme, Nov 17, 2009
    #6
  7. My concern here is when you use libraries. When your user just wants to
    get a list of product categories from the web server, you seem to risk
    Ruby parsing the whole portfolio of library capabilities despite the
    fact you emphatically won't use 99% of them on that transaction.

    Autoload does look as though it addresses this.

    The other solution you mentioned was you put require inside a method and
    then Ruby won't execute it until control passes to the method, so if you
    don't need that method, you don't incur the cost of interpreting it.
    Presumably you can't add classes this way and, from a glance at The Ruby
    Programming Language (Flanagan & Matsumoto), there is a risk the
    included code gets treated as belonging to a different scope to the
    calling method (although that might be a plus point).

    --
    Posted via http://www.ruby-forum.com/.
    Mike Stephens, Nov 17, 2009
    #7
  8. Mike Stephens wrote:
    >
    > My concern here is when you use libraries. When your user just wants to
    > get a list of product categories from the web server, you seem to risk
    > Ruby parsing the whole portfolio of library capabilities despite the
    > fact you emphatically won't use 99% of them on that transaction.


    Not at all. This is what require is for. If you don't require a file,
    it won't be read.

    >
    > Autoload does look as though it addresses this.


    Autoload just automates require AFAIK.

    >
    > The other solution you mentioned was you put require inside a method and
    > then Ruby won't execute it until control passes to the method, so if you
    > don't need that method, you don't incur the cost of interpreting it.
    > Presumably you can't add classes this way


    Of course you can! Why do you think you can't?

    > and, from a glance at The Ruby
    > Programming Language (Flanagan & Matsumoto), there is a risk the
    > included code gets treated as belonging to a different scope to the
    > calling method (although that might be a plus point).


    If you wrap it in a class or module, you get to specify the scope.


    Best,
    --
    Marnen Laibow-Koser
    http://www.marnen.org

    --
    Posted via http://www.ruby-forum.com/.
    Marnen Laibow-Koser, Nov 17, 2009
    #8
  9. On 17.11.2009 19:40, Marnen Laibow-Koser wrote:
    > Mike Stephens wrote:
    >> My concern here is when you use libraries. When your user just wants to
    >> get a list of product categories from the web server, you seem to risk
    >> Ruby parsing the whole portfolio of library capabilities despite the
    >> fact you emphatically won't use 99% of them on that transaction.

    >
    > Not at all. This is what require is for. If you don't require a file,
    > it won't be read.


    Mike's point is, that if you require a library which requires other
    files in turn you might end up loading 50 files although you just need 3
    of them. That overhead can be significant for short lived programs.

    He has a valid point: basically his question is, how do I declare file
    dependencies in complex libraries without immediately "executing" them
    (means: reading all those files)? A good approach here is to use
    autoload alone or a combination of autoload and require as I have done
    in the Muppet Laboratories project (see link below).

    >> Autoload does look as though it addresses this.

    >
    > Autoload just automates require AFAIK.


    Yes, but this is crucial here: autoload will require a file once a
    constant is accessed the first time. And you can even nest it, i.e. use
    it inside a module. That way, if a class is never used at all, you
    won't read that file.

    You can find an example in my project:
    http://github.com/rklemme/muppet-laboratories/blob/master/lib/animal.rb

    >> The other solution you mentioned was you put require inside a method and
    >> then Ruby won't execute it until control passes to the method, so if you
    >> don't need that method, you don't incur the cost of interpreting it.
    >> Presumably you can't add classes this way

    >
    > Of course you can! Why do you think you can't?


    Exactly. The required file can contain anything - from zero to multiple
    classes.

    >> and, from a glance at The Ruby
    >> Programming Language (Flanagan & Matsumoto), there is a risk the
    >> included code gets treated as belonging to a different scope to the
    >> calling method (although that might be a plus point).

    >
    > If you wrap it in a class or module, you get to specify the scope.


    Hmm... I am not aware of any scoping issues right now but you could
    avoid them by anchoring the class name:

    class ::Foo
    end

    That class is always defined in the root namespace.

    Kind regards

    robert


    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
    Robert Klemme, Nov 17, 2009
    #9
  10. Robert Klemme wrote:
    > On 17.11.2009 19:40, Marnen Laibow-Koser wrote:
    >> Mike Stephens wrote:
    >>> My concern here is when you use libraries. When your user just wants to
    >>> get a list of product categories from the web server, you seem to risk
    >>> Ruby parsing the whole portfolio of library capabilities despite the
    >>> fact you emphatically won't use 99% of them on that transaction.

    >>
    >> Not at all. This is what require is for. If you don't require a file,
    >> it won't be read.

    >
    > Mike's point is, that if you require a library which requires other
    > files in turn you might end up loading 50 files although you just need 3
    > of them. That overhead can be significant for short lived programs.


    True.

    >
    > He has a valid point: basically his question is, how do I declare file
    > dependencies in complex libraries without immediately "executing" them
    > (means: reading all those files)? A good approach here is to use
    > autoload alone or a combination of autoload and require as I have done
    > in the Muppet Laboratories project (see link below).
    >
    >>> Autoload does look as though it addresses this.

    >>
    >> Autoload just automates require AFAIK.

    >
    > Yes, but this is crucial here: autoload will require a file once a
    > constant is accessed the first time. And you can even nest it, i.e. use
    > it inside a module. That way, if a class is never used at all, you
    > won't read that file.


    With a better explanation of the library example, now I understand what
    the OP was getting at. You're right.

    >
    > You can find an example in my project:
    > http://github.com/rklemme/muppet-laboratories/blob/master/lib/animal.rb
    >
    >>> The other solution you mentioned was you put require inside a method and
    >>> then Ruby won't execute it until control passes to the method, so if you
    >>> don't need that method, you don't incur the cost of interpreting it.
    >>> Presumably you can't add classes this way

    >>
    >> Of course you can! Why do you think you can't?

    >
    > Exactly. The required file can contain anything - from zero to multiple
    > classes.
    >
    >>> and, from a glance at The Ruby
    >>> Programming Language (Flanagan & Matsumoto), there is a risk the
    >>> included code gets treated as belonging to a different scope to the
    >>> calling method (although that might be a plus point).

    >>
    >> If you wrap it in a class or module, you get to specify the scope.

    >
    > Hmm... I am not aware of any scoping issues right now but you could
    > avoid them by anchoring the class name:
    >
    > class ::Foo
    > end
    >
    > That class is always defined in the root namespace.
    >


    Indeed. I'd be surprised if this were actually necessary, though.

    > Kind regards
    >
    > robert



    Best,
    --
    Marnen Laibow-Koser
    http://www.marnen.org

    --
    Posted via http://www.ruby-forum.com/.
    Marnen Laibow-Koser, Nov 17, 2009
    #10

  11. >
    > Of course you can! Why do you think you can't?
    >
    > Exactly. The required file can contain anything - from zero to multiple
    > classes.


    If I put a class inside a method I get an error, so I assumed if I
    insert code with the word 'class' in it, the same would happen.


    --
    Posted via http://www.ruby-forum.com/.
    Mike Stephens, Nov 18, 2009
    #11
  12. Mike Stephens wrote:
    >
    >>
    >> Of course you can! Why do you think you can't?
    >>
    >> Exactly. The required file can contain anything - from zero to multiple
    >> classes.

    >
    > If I put a class inside a method I get an error, so I assumed if I
    > insert code with the word 'class' in it, the same would happen.


    In that light, it's a reasonable assumption, but I don't think it's
    right. require is not *exactly* the same as literal inclusion. Have
    you had a chance to try it yet?


    Best,
    --
    Marnen Laibow-Koser
    http://www.marnen.org

    --
    Posted via http://www.ruby-forum.com/.
    Marnen Laibow-Koser, Nov 18, 2009
    #12
  13. Mike Stephens

    pharrington Guest

    On Nov 18, 2:56 am, Mike Stephens <> wrote:
    > > Of course you can!  Why do you think you can't?

    >
    > > Exactly.  The required file can contain anything - from zero to multiple
    > > classes.

    >
    > If I put a class inside a method I get an error, so I assumed if I
    > insert code with the word 'class' in it, the same would happen.
    >
    > --
    > Posted viahttp://www.ruby-forum.com/.



    Because

    def asdf; class Edgar; end; end

    is a syntax error is all; of course nothing in Ruby is stopping you
    from creating a new class within a method call. If you really want or
    need to is a different question entirely.
    pharrington, Nov 18, 2009
    #13
  14. Mike Stephens

    Gary Wright Guest

    On Nov 18, 2009, at 12:57 PM, Marnen Laibow-Koser wrote:

    > Mike Stephens wrote:
    >>
    >>>
    >>> Of course you can! Why do you think you can't?
    >>>
    >>> Exactly. The required file can contain anything - from zero to
    >>> multiple
    >>> classes.

    >>
    >> If I put a class inside a method I get an error, so I assumed if I
    >> insert code with the word 'class' in it, the same would happen.

    >
    > In that light, it's a reasonable assumption, but I don't think it's
    > right. require is not *exactly* the same as literal inclusion. Have
    > you had a chance to try it yet?


    In fact it is very different from textual inclusion and it will only
    serve to confuse if you try to draw analogies to textual inclusion.

    Gary Wright
    Gary Wright, Nov 18, 2009
    #14
  15. On Tue, 17 Nov 2009, Brian Candler wrote:

    > David A. Black wrote:
    >> the code is executed as it's encountered, and you get output before
    >> and after the execution of the method definition. (Of course the
    >> method body isn't executed until there's an object to which to send
    >> the "x" method.)

    >
    > Except: when reading in a source file there is an initial parsing step
    > to build the syntax tree, and if that fails then you get a parse error
    > and nothing is executed. Mismatched 'end' statements will do that, for
    > example.


    I hadn't gotten into parsing just to keep it simple -- but in fact, it
    does appear to be a parse-time/syntax error, rather than a runtime
    error, which I hadn't noticed.


    David

    --
    THE COMPLEAT RUBYIST, Ruby training with Black/Brown/McAnally!
    January 22-23, Tampa, Florida
    Info and registration at http://www.thecompleatrubyist.com
    --------------------------------------
    My new job: http://tinyurl.com/yfpn9hz
    David A. Black, Nov 19, 2009
    #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. Mike Wilmot
    Replies:
    0
    Views:
    3,266
    Mike Wilmot
    Dec 15, 2003
  2. Carlos Oliveira
    Replies:
    0
    Views:
    18,902
    Carlos Oliveira
    Aug 19, 2004
  3. Peter Szinek
    Replies:
    4
    Views:
    118
    Robert Dober
    Apr 27, 2011
  4. London Boy
    Replies:
    2
    Views:
    310
    Keith Bowes
    Jan 12, 2004
  5. Replies:
    5
    Views:
    194
    A. Sinan Unur
    Sep 8, 2005
Loading...

Share This Page