DEV Community

loading...

Ruby: class methods vs. instance methods

adamlombard profile image Adam Lombard (he/him) Updated on ・1 min read

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 (he/him) 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

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!

Forem Open with the Forem app