Is there any difference in how class_eval
& instance_eval
work except def
? Inside class_eval
block def
defines method to class itself (i.e. instance method) and inside instance_eval
def
defines method to the eigenclass of the class (i.e. class method). AFAIK all other features work identically in both cases (e.g. define_method
, attr_accessor
, class << self; end
, defining constants). Is it true?
Answer is: def
, undef
and alias
have different contexts for class_eval
and instance_eval
.
class_eval is a method of the Module class, meaning that the receiver will be a module or a class. The block you pass to class_eval is evaluated in the context of that class. Defining a method with the standard def keyword within a class defines an instance method, and that's exactly what happens here.
instance_eval(array_second) adds the method second to the variable a — which is an instance of Array — by passing a String that will be evaluated in the context of the instance a . The call to str. instance_eval with a block will evaluate the content of the block in the context of str — which is an instance of String .
class_eval(array_second) adds the method second to any instance of Array by passing a String that will be evaluated in the context of the class Array . The call to String. class_eval with a block will evaluate the content of the block in the context of the class String .
Long story short:
Object.instance_eval &block
sets:
self
to Object
Object.singleton_class
Object.class_eval &block
sets:
self
to Object
Object
The "current class" is used for def
, undef
and alias
, as well as constant and class variable lookups.
Now, let's have a look at the implementation details.
Here's how module_eval
and instance_eval
are implemented in C:
VALUE rb_mod_module_eval(int argc, VALUE *argv, VALUE mod) {
return specific_eval(argc, argv, mod, mod);
}
VALUE rb_obj_instance_eval(int argc, VALUE *argv, VALUE self) {
VALUE klass;
if (SPECIAL_CONST_P(self)) { klass = Qnil; }
else { klass = rb_singleton_class(self); }
return specific_eval(argc, argv, klass, self);
}
Both call specific_eval
, which takes the following arguments: int argc
, VALUE *argv
, VALUE klass
and VALUE self
.
Note that:
module_eval
passes the Module
or Class
instance as both klass
and self
instance_eval
passes the object's singleton class as klass
If given a block, specific_eval
will call yield_under
, which takes the following arguments: VALUE under
, VALUE self
and VALUE values
.
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
return yield_under(klass, self, Qundef);
}
There are two important lines in yield_under
:
block.self = self;
This sets the self
of the block to the receiver.
cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
The cref
is a linked list
which specifies the "current class", which is used for def
, undef
and alias
, as well
as constant and class variable lookups.
That line basically sets the cref
to under
.
Finally:
When called from module_eval
, under
will be the Class
or Module
instance.
When called from instance_eval
, under
will be the singleton class of
self
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With