Henry Yang
Henry Yang

Reputation: 2623

How does ruby tell the difference between instance method and class method definition?

In normal ruby code, I can normally omit self:

class User
  def greeting
    # these 2 are the same:
    puts "Hi, #{name}"
    puts "Hi, #{self.name}"
  end
end

but why are these 2 different:

# 1
class User
  def self.greeting
    # ...
  end
end

# 2
class User
  def greeting
    # ...
  end
end

Why can't I just omit the self? What's the difference here to ruby code compiler's perspective?

I know #1 is class method definition (Singleton method definition) and #2 is instance method definition. But how did ruby work with context and self to arrive at this difference in method definition?

Upvotes: 1

Views: 484

Answers (6)

Cary Swoveland
Cary Swoveland

Reputation: 110755

Methods defined on a class are instance methods:

class Animal
  def dog
    "woof"
  end

  def cat
    "meow"
  end
end

They are so-named because they respond to any instance of the class, meaning that their receiver must be an instance of the class:

Animal.instance_methods(false)
  #=> [:dog, :cat] 
animal = Animal.new
  #=> #<Animal:0x00005bfb0c55ae98>  
animal.dog
  #=> "woof"
Animal.dog
  #=> NoMethodError (undefined method `dog' for Animal:Class)

To define a method whose receiver is a class (a class method) we define the method on the class's singleton class. For the class Animal we could write either of the following.

class Animal
  class << Animal
    def pig(n)
      "#{n} little pigs"
    end
  end
end

Animal.methods(false)
  #=> [:pig] 
Animal.pig(3)
  #=> "3 little pigs"

or

Animal.define_singleton_method(:pig) do |n|
  "#{n} little pigs"
end

Animal.methods(false)
  #=> [:pig] 
Animal.pig(3)
  #=> "3 little pigs"

The line class < Animal1 changes the scope to Animal's singleton class, causing the value of self to change to that class as well.

So what does this have to do with the question, that is, defining methods def self.my_method ...? The short answer is that there is no need to define methods in that way. Please be patient--I'll get to that.

Note that the method pig, defined on Animal's singleton class, is inherited by the singleton class of subclasses of Animal:

class Swine < Animal
end

Swine.instance_methods & [:dog, :cat]
  #=> [:dog, :cat]
Swine.methods & [:pig]
  #=> [:pig] 

We can also define methods on many unique objects. Consider animal, an instance of Animal:

animal.define_singleton_method(:rodent) do |n|
  "I'm rodent ##{n}"
end

animal.rodent(3241)
  #=> "I'm rodent #3241"

animal is the only receiver to which this method will respond:

Animal.new.rodent(55)
  #=> #NoMethodError (undefined method `rodent' for
  #     #<Animal:0x00005bfb0c530670>)

In fact, we can define methods on every object that has a singleton class, which is most objects:

str = "cow"
str.define_singleton_method(:greeting) { "moo" }
str.greeting
  #=> "moo"

arr = [1,2]
arr.define_singleton_method(:greeting) { "I'm an array" }
arr.greeting
  #=> "I'm an array"

module M; end
M.define_singleton_method(:greeting) { "I'm a module" }
M.greeting
  #=> "I'm a module"

piggy = Animal.method(:pig)
  #=> #<Method: Animal.pig> 
piggy.define_singleton_method(:greeting) { 
  "I'm a singleton method" }
piggy.greeting
  #=> "I'm a singleton method"

We can do this with all Ruby objects that have a singleton class. That comprises all objects except those having immediate values (objects passed by value), which include nil, true, false, Integers, Symbols, and some Floats. In addition, objects that have been frozen (e.g., "Hi".freeze) do not have a singleton class.

Suppose now we write

class Animal
  def Animal.pig(n)
    "#{n} little pigs"
  end
end

or (same thing)

class Animal
  def self.pig(n)
    "#{n} little pigs"
  end
end

(We're finally there!)

What is this new way of defining a method? It is in fact just a shorthand way of defining a method on Animal's singleton class. Think of it as merely syntactic sugar. Just as writing 2 + 2 instructs Ruby to execute 2.+(2), Animal. or self. in the first line of the method definition merely instructs Ruby to execute the following.

class Animal
  class << self
    def pig(n)
      "#{n} little pigs"
    end
  end
end

In other words, the creation of class method by writing def Animal.my_method... or def self.my_method... is not needed at all; it is there merely as a convenience for Ruby coders.

1 That line would generally be written class << self, which is acceptable as self equals Animal when the line is executed. Using << self is merely a convenience should the class be renamed.

Upvotes: 1

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369614

First of all, it is important to understand that there is no such thing as class method or a singleton method in Ruby. There is only exactly one kind of methods: instance methods.

The real question is: what module is the method defined in?

["Singleton method" and "class method" are simply shorthand names that we use for "method that is defined in the singleton class" and "method that is defined in the singleton class of an object whose class is Class".]

There are two forms of method definitions in Ruby:

def some_expression.some_name; end

and

def some_name; end

The first one will first evaluate the expression some_expression and then define a method named some_name inside the singleton class of the resulting object.

The second one will define a method named some_name in what is called the default definee. The default definee is usually the closest lexically enclosing module definition. For example, in this case:

module Foo
  module Bar
    def foo
      def bar; end
    end
  end
end

include Foo::Bar

foo
# At this point, `bar` will be defined, but where?

Here, bar will be defined as an instance method of Foo::Bar, because bar is the closest lexically enclosing module definition. There is another lexical definition that is even closer, namely the method definition of foo, but that is not a module definition.

A little bit more puzzling:

Foo = Class.new do
  def foo; end
end

This will define foo as an instance method of Foo, even though technically this is not a module definition, it is "just" a block. However, that's why I wrote "usually" above: some methods can change the default definee, and Class::new is one of those methods (similar to how, e.g. Object#instance_eval changes the value of self).

Another example:

def foo; end

In this case, there is no lexically enclosing module definition. At the top-level, the default definee is Object but with a twist: the default visibility is also private.

All of this is explained in greater detail in the brilliant blog post Three implicit contexts in Ruby by yugui.

Now, the only thing missing is: what does the expression self evaluate to inside a module definition? Well, you can test it out if you want:

class Foo
  p self
end

The answer is that inside a module definition, self evaluates to the module being defined. (Kind of makes sense, does it?)

Therefore, in

class Foo
  def self.foo; end
end

foo is defined in the singleton class of Foo.

Upvotes: 0

sawa
sawa

Reputation: 168269

In a method body, self refers to the receiver. In lines 3..4 of the following, once the receiver is determined to be a User instance (by the def greeting syntax), self refers to that instance.

class User
  def greeting
    puts "Hi, #{name}"      # method body
    puts "Hi, #{self.name}" # method body
  end
end

In a class body, self refers to the class. In lines 2, 4, 8, 10 of the following, the class is User, so def self.greeting is the same as def User.greeting.

class User
  def self.greeting # class body
    # ...
  end               # class body
end

class User
  def greeting      # class body
    # ...
  end               # class body
end

But I actually think your real issue is not what self means, but rather what "an omitted receiver" means, in different contexts.

In method-calling syntax, an omitted receiver stands for self. So the following two are the same:

name
self.name

In method-defining syntax, an omitted receiver stands for "any instance of the class". So the following two are not the same:

def User.greeting; ... end
def greeting; ... end

When you define an instance method, there is no explicit way to express "any instance of the class", so actually omission is mandatory.

Upvotes: 5

ray
ray

Reputation: 5552

self is mandatory while defining class methods whereas without self keyword it will be treated as instance methods. class << self; end; block also used to define numbers of class methods.

These methods are loaded when your class is loaded and above will help to distinguish them.

It will be simply like relating with real life example.

You have number of accounts having authentication provided on your computer, valid person with right password can enter inside account. Once you enter inside account, you do not need to mention who you are! It always count you the one who entered.

Upvotes: 0

David
David

Reputation: 1970

The self is sometimes needed (otherwise it wouldn't exist at all). The first example you give is a case where it is redundant. Both of those method calls refer to the same method.

There are times when it is needed to distinguish between two different behaviours.

In your examples #1 and #2 the self is used to make sure the method is defined on the class, rather than being on instances of the class. The self isn't redundant in this case. This is the way that the Ruby interpreter knows where you want the method defined. It might be helpful to think about the self in your very first example as a different thing to the self in examples #1 and #2. It might be helpful to think of the self in #1 and #2 as "class"? They're the same keyword but how they are used is not directly interchangeable.

Another example of where it isn't redundant:

# user.rb

def method1
  name = "Henry" # Sets a local variable called `name`
end

def method2
  self.name = "Henry" # Sets the user's `name` attribute
end

Upvotes: 3

philnash
philnash

Reputation: 73100

In a class if you define a method on self, it defines it on the class. E.g.

class User
  def self.greeting
    "Hello User"
  end
end

Then you can call

User.greeting
# => "Hello User"

If you define a method without self, then that method is defined for objects of that class. E.g.:

class User
  def greeting
    "Hello user"
  end
end

Then you have to create a new user object to call greeting.

user = User.new
user.greeting
# => "Hello user"

Upvotes: 0

Related Questions