When you get farther upwards the steep hill that is Ruby mastery, you will come across some powerful, yet slightly evil methods: instance_eval and class_eval¹. They allow you to execute code and define methods tied to a specific class, at the same time giving you access to outer scope variables through the Ruby block syntax. Their exact behavior varies, depending on the context they are used in. So what is the difference between all the evals?
¹ Also aliased as module_eval
Eval / Method Definition Comparison
In the following tables, you will find all combinations of defining a method and executing it in a different class context:
Class Scope
Definition Method | No eval |
class_eval |
instance_eval |
---|---|---|---|
def |
instance | instance | class |
define_method |
instance | instance | instance |
def self. |
class | class | class |
define_singleton_method |
class | class | class |
Class-Class Scope (class << self
)
Definition Method | No eval |
class_eval |
instance_eval |
---|---|---|---|
def |
class | class | class-class |
define_method |
class | class | class |
def self. |
class-class | class-class | class-class |
define_singleton_method |
class-class | class-class | class-class |
Observations
While class_eval
behaves exactly as if it was in no eval-context at all, instance_eval
features a notable difference:
def inside instance_eval will define methods one class-level higher. So when instance_eval
is executed on instances, def
will create instance methods instead of singleton methods. And when it is run on classes, def
will create class methods instead of instance methods.
Another difference is that while class_eval
is defined on Module, instance_eval
lives in BasicObject allowing you to use it on any object, not only modules and classes. However, there is a simple way to use class_eval
for instances, too. You can explicitly use the object's singleton class (class << self
), which is a module:
o = Object.new # => #<Object:0x000055b6fdabf1f8>
o.singleton_class.class_eval do
def m
p self
end
end
o.m # => #<Object:0x000055b6fdabf1f8>
Best Practice
Overall, the behavior of instance_eval
is rather confusing and my recommendation is to avoid it and always use class_eval
. If you do not need closure access, consider using no eval at all.
Reference / Examples: Class-Level Scope
For reference, what follows is a list of snippets illustrating each eval-define combination.
Class / def
Defines method on instance-level
class C
def m
p self
end
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / class_eval
+ def
Defines method on instance-level
class C
class_eval{
def m
p self
end
}
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / instance_eval
+ def
Defines method on class-level
class C
instance_eval{
def m
p self
end
}
end
C.m # => C
Class / define_method
Defines method on instance-level
class C
define_method(:m){
p self
}
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / class_eval
+ define_method
Defines method on instance-level
class C
class_eval{
define_method(:m){
p self
}
}
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / instance_eval
+ define_method
Defines method on instance-level
class C
instance_eval{
define_method(:m){
p self
}
}
end
C.new.m # => #<C:0x0000556efd3eb1a8>
Class / def self.
Defines method on class-level
class C
def self.m
p self
end
end
C.m # => C
Class / class_eval
+ def self.
Defines method on class-level
class C
class_eval{
def self.m
p self
end
}
end
C.m # => C
Class / instance_eval
+ def self.
Defines method on class-level
class C
instance_eval{
def self.m
p self
end
}
end
C.m # => C
Class / define_singleton_method
Defines method on class-level
class C
define_singleton_method(:m){
p self
}
end
C.m # => C
Class / class_eval
+ define_singleton_method
Defines method on class-level
class C
class_eval{
define_singleton_method(:m){
p self
}
}
end
C.m # => C
Class / instance_eval
+ define_singleton_method
Defines method on class-level
class C
instance_eval{
define_singleton_method(:m){
p self
}
}
end
C.m # => C
Reference / Examples: Class-Class-Level Scope
Class-Class / def
Defines method on class-level
class C
class << self
def m
p self
end
end
end
C.m # => C
Class-Class / class_eval
+ def
Defines method on class-level
class C
class << self
class_eval{
def m
p self
end
}
end
end
C.m # => C
Class-Class / instance_eval
+ def
Defines method on class-class-level
class C
class << self
instance_eval{
def m
p self
end
}
end
end
C.singleton_class.m #=> #<Class:C>
Class-Class / define_method
Defines method on class-level
class C
class << self
define_method(:m){
p self
}
end
end
C.m # => C
Class-Class / class_eval
+ define_method
Defines method on class-level
class C
class << self
class_eval{
define_method(:m){
p self
}
}
end
end
C.m # => C
Class-Class / instance_eval
+ define_method
Defines method on class-level
class C
class << self
instance_eval{
define_method(:m){
p self
}
}
end
end
C.m # => C
Class-Class / def self.
Defines method on class-class-level
class C
class << self
def self.m
p self
end
end
end
C.singleton_class.m # => C
Class-Class / class_eval
+ def self.
Defines method on class-class-level
class C
class << self
class_eval{
def self.m
p self
end
end
}
end
C.singleton_class.m #=> #<Class:C>
Class-Class / instance_eval
+ def self.
Defines method on class-class-level
class C
class << self
instance_eval{
def self.m
p self
end
}
end
end
C.singleton_class.m #=> #<Class:C>
Class-Class / define_singleton_method
Defines method on class-class-level
class C
class << self
define_singleton_method(:m){
p self
}
end
end
C.singleton_class.m # => C
Class-Class / class_eval
+ define_singleton_method
Defines method on class-class-level
class C
class << self
class_eval{
define_singleton_method(:m){
p self
}
}
end
end
C.singleton_class.m #=> #<Class:C>
Class-Class / instance_eval
+ define_singleton_method
Defines method on class-class-level
class C
class << self
instance_eval{
define_singleton_method(:m){
p self
}
}
end
end
C.singleton_class.m #=> #<Class:C>
Also See
More Idiosyncratic Ruby
- Please Comment on GitHub
- Next Article: What the Regex?
- Previous Article: Less Feature-Rich, More Fun