DEV Community

Adam Lombard
Adam Lombard

Posted on • Updated on

Ruby: class methods vs. instance methods

In Ruby, a method provides functionality to an Object. A class method provides functionality to a class itself, while an instance method provides functionality to one instance of a class.

Consider the following Ruby class:

class SayHello
  def self.from_the_class
    "Hello, from a class method"
  end

  def from_an_instance
    "Hello, from an instance method"
  end
end
Enter fullscreen mode Exit fullscreen mode

This would yield the following:

>> SayHello.from_the_class
=> "Hello, from a class method"

>> SayHello.from_an_instance
=> undefined method `from_an_instance' for SayHello:Class


>> hello = SayHello.new
>> hello.from_the_class
=> undefined method `from_the_class' for #<SayHello:0x0000557920dac930>

>> hello.from_an_instance
=> "Hello, from an instance method"
Enter fullscreen mode Exit fullscreen mode

We cannot call an instance method on the class itself, and we cannot directly call a class method on an instance.

Railstips has a nice article with more detail and a discussion of alternative ways of creating both class methods and instance methods.


See also: Python: class vs. instance vs. static methods

Discussion (4)

Collapse
citizen428 profile image
Michael Kohl

The nice thing about Ruby's object model is that class methods are really nothing special: SayHello itself is an instance of class Class and from_the_class is a singleton method defined on this instance (as opposed to instance methods of Class that all instances share):

SayHello.singleton_methods
#=> [:from_the_class]
Enter fullscreen mode Exit fullscreen mode

Conceptually this is the same as defining a singleton method on any other object:

s = 'dev.to'

def s.yell
  'DEV.TO'
end

s.yell
#=> "DEV.TO"

s.singleton_methods
#=> [:yell]

# alternatively
# class << s
#   def s.yell
#     'DEV.TO'
#   end
# end
Enter fullscreen mode Exit fullscreen mode
Collapse
adamlombard profile image
Adam Lombard Author

Thanks for the deeper dive on that, Michael!

Collapse
mth0158 profile image
Mathieu EUSTACHY

Thanks for this @citizen428 !

Collapse
son1112 profile image
Anderson Reinkordt • Edited on

I am playing with a decision to define an instance method within a module, that acts as a 'proxy' to the class method of the same name.

For example, let's say the following exists in a module:

default = foobarbitz_entangling_thing.raw_metadata.dig("ooooooh_realllly?") == true ? self.class.ready_to_start_digggging_early_at : self.class.ready_to_start_diggggging_at

def self.ready_to_start_diggggging_at
  ... does things
end

def self.ready_to_start_digggging_early_at
  ... does things
end
Enter fullscreen mode Exit fullscreen mode

I want to reduce the length of the 'default' assignment. The condition statement reduction is trivial for the first part, so it ends up looking like this with a helper method:

default = oooh_realllly? ? self.class.ready_to_start_digggging_early_at : self.class.ready_to_start_diggggging_at
Enter fullscreen mode Exit fullscreen mode

I would like to add the following simply for reducing this line length as minimally as possible.

def ready_to_start_diggggging_at
  self.class.ready_to_start_diggggging_at
end

def ready_to_start_digggging_early_at
  self.class.ready_to_start_digggging_early_at
end
Enter fullscreen mode Exit fullscreen mode

This reduces the line to about here:

default = oooh_realllly? ? ready_to_start_digggging_early_at : ready_to_start_diggggging_at
Enter fullscreen mode Exit fullscreen mode

Aside from renaming methods to reduce length, my question is this:

Is this bad practice, bad pattern, a bad dog that will bite me later? Or is this okay and common practice?

It feels weird to me to call a module's defined class method from that same module's instance method of the same name. The other way around, sure that happens all of the time. I am hesitating; probably for good reason?

Note: These are silly method names created just for an example of a long method name. For context, I am attempting to do this minimally, so I am avoiding method name changes and anything else really that will add to review discussion rabbit holes. KISS

Thanks for taking time read this!