rubyclassinstance-methods

When do I need to use self.instance_method vs instance_method alone?


I'm hoping someone can explain why I get the same behavior from both of these methods and what that means for when to or not to use self.

def my_instance_method(arg)
  'execute some code' if another_instance_method_of_same_class?(arg)
end

seems to behave exactly the same as

def my_instance_method(arg)
  'execute some code' if self.another_instance_method_of_same_class?(arg)
end

My apologies if my search skills aren't up to par but I couldn't find the exact answer to this question, just explanations of what self does (which made me think I should need it). I'm using the latest version of Ruby. Thank you.


Solution

  • There are a few differences between self.foo(...) and foo(...), but they're mostly equivalent.

    Privacy

    private methods can only be called via foo directly, and never with an explicit receiver. So if foo is marked private, then you have to call it without self.

    class Example
    
      private def foo(x)
        x + 1
      end
    
      def bar
        foo # Works fine
        self.foo # Error: foo is private
      end
    
    end
    

    Shadowing

    If you have a local variable called foo in the current function, then writing foo without arguments will reference the local variable instead

    class Example
    
      def foo(*args)
        puts "Hello :)"
      end
    
      def bar
        foo = 100 # Just an ordinary variable; no relation to the above method
        foo # This refers to the local variable called "foo"
        self.foo # This calls the method foo() with no arguments
        foo(1) # This calls the method foo() with one argument
        self.foo(1) # Equivalent to the above; calls with one argument
      end
    
      def baz
        foo # There's no local variable called "foo", so this calls the method
      end
    
    end
    

    Assignment

    If the method you're talking about is an assignment method (i.e. ends in =), then it must always be called with an explicit receiver

    class Example
    
      def foo=(value)
        puts "Assigning foo = #{value}"
      end
    
      def bar
        foo = 0 # This creates a new local variable called foo and assigns to it
        self.foo = 0 # Calls foo= on self
      end
    
    end