Sat27Mar

  1. class_eval vs instance_eval

    In Ruby you may have seen class_eval and instance_eval and thought to yourself “What is the difference?” They both accept a string or a block as an argument, but then they diverge:

    instance_eval evaluates a string as Ruby code or a block in the context of the object’s singleton class. Effectively it changes the value of self, the implicit receiver, to be that of the object’s metaclass, singleton class, eigenclass, or whatever else you may know it as.

    Methods on an object’s singleton class are defined on that object. If you call it on an instance of a class, the code evaluated by instance_eval will only apply to that instance. 

    instance_eval is not the only way to define singleton methods in Ruby. As usual in Ruby, there is a multitude of ways to skin a cat: 

    dude = "steve"
    
    # All these are equivalent
    
    class << dude
      def say_what_up
        "yo, my name is #{self}"
      end
    end
    
    def dude.say_what_up
      "yo, my name is #{self}"
    end
    
    dude.instance_eval do
      def say_what_up
        "yo, my name is #{self}"
      end
    end

    When you call it on an actual class, it has the effect of defining “class methods”. I put that in quotes because once you think of it in those terms it becomes clear that “class methods” do not actually exist, they are just singleton methods on another type of object, i.e. a class. Amazing!

    class Foo
      def self.foo
        "foo"
      end
    end
    
    class Foo
      class << self
        def foo
          "foo"
        end
      end
    end
    
    def Foo.foo
      "foo"
    end
    
    class << Foo
      def foo
        "foo"
      end
    end
    
    Foo.instance_eval do
      def foo
        "foo"
      end
    end
    

    These all do the same thing, i.e. define the “class method” Foo.foo that returns a string “foo”.

    So I did say earlier that code evaluated by instance_eval will only apply to that object. That’s not strictly true, although semantically it is. If you call on an actual class, it will be visible to classes that subclass it when Ruby can’t find it on that object. Ruby then goes off on its merry way up the inheritance chain looking for it in ancestor classes.

    Like so:

    Foo = Class.new
    
    Foo.instance_eval do
      def foo
        "foo"
      end
    end
    
    Bar = Class.new Foo
    
    puts Bar.foo
    
    #=> foo

    class_eval

    class_eval switches the value of self to its receiver. This can only be called on a module or class and not an instantiation of those objects. A method defined in a string or block supplied to instance_eval has the effect of defining instance methods for that class or module. (Although a module cannot be instantiated, it can be mixed into a class, making the class respond to those instance methods. More on this at a later date.)

    class Foo
      def to_s
        "foo"
      end
    end
    
    Foo.class_eval do
      def to_s
        "foo"
      end
    end

    class_eval is also aliased as module_eval. I tend to use module_eval if the object that I’m manipulating is a module as opposed to a class. I think it makes my code more readable and is a good style to adopt.

    You can’t use class_eval on an object instance. Try it, you’ll get a NoMethod error. This makes perfect sense!

    That’s all I can think of for now

    S