Skip to content
loading...

Prefer Ruby Class Method or Mix-In Instance Method?

burdettelamar profile image Burdette Lamar github logo ・1 min read

Assume that a certain functionality is available in Ruby both as a class method and as an instance method (via a module).

Class method:

require 'foo'  
Foo.foo()  

Instance method (via module):

require 'bar'    
include Bar    
bar()    

Assuming that the two methods behave identically, which would you prefer using, and why?

(Note that the question is not about which to implement, but instead about which to use if both available.)

twitter logo DISCUSS (4)
Discussion
markdown guide
 

A require 'foo' does not alter your class. It just gives you access to call Foo.foo(). There's nothing happening in terms of inheritance or composition. It's maybe the simplest form of dependency between your class and Foo. If you only want to call one method or another in Foo, then yes, that's the way to go.

But when calling include Bar there's a lot happening. You not only get access to bar(), but also to all other methods that are in Bar. And they are directly available in the namespace of your instance. And maybe even class methods have been defined, so the include might have also given you YourClass.baz(). You better know exactly what's in Bar, because your class might get cluttered with a lot of stuff... it's actually pretty similar to inheritance. So the actual question when it comes to include is: ruby inheritance vs. mixins. And I like this answer very much:

Modules are for sharing behavior, while classes are for modeling relationships between objects.

So back to your question - you should use include when you want your class to get (all) the behaviour the module gives you. And you should not use it if you just want to call a method.

 

I would prefer the first, because calling Foo.foo clearly shows the receiver of the method, and I know that bar is probably defined in foo.rb.

In the second example, it's less clear where bar is defined. Ok, it's clear in your example, but in a situation where the names aren't so simple, bar might be defined in the current class, or bar.rb, or any other module that's mixed into the current class, or all three.

 

I think the include is most useful as used in Enumerable, e.g. a base class implements a few simple methods, and then by including a module that leverages those simple methods, gets a lot of syntactic sugar on top.

class methods, (consider prefixing your module with module_function and all methods will be accessible as class methods) are a way of pushing Ruby to be more functional.

It's not one vs the other, but rather, two different tools wrapped in one name, module.

Generally, though, I agree with some of the other commenters that class methods are king. But also: if you're going to lean on class methods so much, it might make sense to try to use another language that enforces those patterns, e.g. most functional programming languages. Elixir? Elm?

Classic DEV Post from Jul 30 '19

PublishTo.Dev: Scheduling article publishing on dev.to

Burdette Lamar profile image
Started out teaching English at Embry-Riddle. Graded 10,000 essays. Lesson learned. Became a mathematics teacher. Discovered computing. Never looked back.