Instance_eval && class_eval

Hi,

I'm just studing some metaprogramming and came across some problems.
The following code:

···

####################
class D
  instance_eval do
    define_method("i_method") do
      print "\nin i_method"
    end
    def ii_method
      print "\nin ii_method"
    end
  end
  class_eval do
    define_method("c_method") do
      print "\nin c_method"
    end
    def cc_method
      print "\nin cc_method"
    end
  end
end

D.new.i_method
D.ii_method
D.new.c_method
D.new.cc_method

D.i_method
##################

results in

in i_method
in ii_method
in c_method
in cc_method
metaruby2.rb:163: undefined method `i_method' for D:Class (NoMethodE
rror)

so why is

D.i_method wrong and
D.new.i_method correct?

BTW, I know the right way of solving this, but I'm somehow missing
something which would explain it to me in a consitent manner

here the solution:
class D
  (class << self; self; end).instance_eval do #class_eval also does
the job
    define_method( :iii_method ) do
      print "\nin iii_method"
    end
  end
end

D.iii_method

which works fine.

Artur

define_method defines an instance method both in the instance_eval and class_eval sections of your code. To be able to call

   D.method

method needs to be a class instance method of D (i.e. a method of the singleton class of D herself).

-- fxn

···

On Oct 21, 2006, at 12:55 PM, Artur Merke wrote:

Artur Merke wrote:

so why is
D.i_method wrong and
D.new.i_method correct?

I'm not surprised by that. I'm surprised that standard def...end syntax
inside instance_eval behaves differently from being in the class scope,
when the self object in both cases is the same.

irb(main):001:0> class Foo
irb(main):002:1> p "Defining aa in #{self}##{self.object_id}"
irb(main):003:1> def aa; p :aa; end
irb(main):004:1> instance_eval{
irb(main):005:2* p "Defining bb in #{self}##{self.object_id}"
irb(main):006:2> def bb; p :bb; end
irb(main):007:2> }
irb(main):008:1> end
"Defining aa in Foo#1699170"
"Defining bb in Foo#1699170"
=> nil
irb(main):009:0> Foo.new.aa
:aa
=> nil
irb(main):010:0> Foo.bb
:bb
=> nil

Xavier Noria schrieb:

define_method defines an instance method both in the instance_eval
and class_eval sections of your code. To be able to call

   D.method

method needs to be a class instance method of D (i.e. a method of the
singleton class of D herself).

yes (see also my solution I provided at the end of my msg), but this
was not the question,

the question was (and still is), why(!)

def a
end

and

define_method(:a) do
end

behave differently in instance_eval (and not in class_eval and anywhere
else) ...

AHA

Artur

···

On Oct 21, 2006, at 12:55 PM, Artur Merke wrote:

I'm not surprised by that. I'm surprised that standard def...end syntax
inside instance_eval behaves differently from being in the class scope,
when the self object in both cases is the same.

def is a keyword and it don't use self to know where the method must be
defined but it use an "internal" variable the "current" class.

irb(main):001:0> class Foo

here you have

                    self = current class = Foo

irb(main):002:1> p "Defining aa in #{self}##{self.object_id}"
irb(main):003:1> def aa; p :aa; end
irb(main):004:1> instance_eval{

in instance_eval you have
                
                      self = Foo
                      current class = Foo singleton class

irb(main):005:2* p "Defining bb in #{self}##{self.object_id}"
irb(main):006:2> def bb; p :bb; end

Guy Decoux

Ah yes, I see it now. I join the question, a posteriori looks like within instance_eval we are in the context of the singleton class of D, because D.ii_method works. But puts self does not seem to output that one there

   irb(main):010:0> class D; instance_eval do; puts self; end; end
   D
   => nil
   irb(main):011:0> class D; puts (class << self; self; end); end
   #<Class:D>
   => nil

so I don't understand it either.

-- fxn

···

On Oct 21, 2006, at 2:45 PM, Artur Merke wrote:

the question was (and still is), why(!)

def a
end

and

define_method(:a) do
end

behave differently in instance_eval (and not in class_eval and anywhere
else) ...

Good!

Is the existence of that "current" class vs self documented somewhere or do you know it from the sources? Does it have a name in jargon? What about the fact that instance_eval switches current to the singleton class of self? I saw it works for objects which are not classes as well (which is a redundant exercise to reinforce this):

   class A
   end

   a = A.new
   b = A.new

   a.instance_eval do
     def croak
       puts "croak!"
     end
   end

   a.croak
   b.croak

gives

   croak!
   tmp/foo.rb:13: undefined method `croak' for #<A:0x1e6374> (NoMethodError)

so the "current" class is the singleton class of the object a as well.

-- fxn

···

On Oct 21, 2006, at 3:40 PM, ts wrote:

> I'm not surprised by that. I'm surprised that standard def...end syntax
> inside instance_eval behaves differently from being in the class scope,
> when the self object in both cases is the same.

def is a keyword and it don't use self to know where the method must be
defined but it use an "internal" variable the "current" class.

Is the existence of that "current" class vs self documented somewhere
or do you know it from the sources? Does it have a name in jargon?

ruby_class : it's in the source, this mean that it's documented :slight_smile:

What about the fact that instance_eval switches current to the
singleton class of self? I saw it works for objects which are not
classes as well (which is a redundant exercise to reinforce this):

Well a class can be seen as an object or as a class, i.e. with a class
you can define a singleton method or a method.

#instance_eval work with any object, and in this case a class is just an
  object like any other and def will define a singleton method

#class_eval work only with classes (and modules) and in this case def will
  define instance methods.

Guy Decoux