Class inside a Method Body

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

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

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

Hi --

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

···

On Tue, 17 Nov 2009, Mike Stephens wrote:

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

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.

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

Kind regards

robert

···

2009/11/17 Mike Stephens <rubfor@recitel.net>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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

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 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
marnen@marnen.org
--
Posted via http://www.ruby-forum.com/\.

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

···

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.

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

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:

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

···

On 17.11.2009 19:40, Marnen Laibow-Koser wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme 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:
muppet-laboratories/lib/animal.rb at master · rklemme/muppet-laboratories · GitHub

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,

···

On 17.11.2009 19:40, Marnen Laibow-Koser wrote:

--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
--
Posted via http://www.ruby-forum.com/\.

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 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
marnen@marnen.org
--
Posted via http://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.

···

On Nov 18, 2:56 am, Mike Stephens <rub...@recitel.net> 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/.

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

···

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?