Class methods are the source for continuous discussions and disagreements among my colleagues. While some consider them precise and helpful, others feel they are actually pesky and that they tend to make code harder to read and manage. As for me, I find that the truth tends to lean to the latter; I embrace Ruby?s OO nature and I like to think (and read!) in objects. Having said that, sometimes class methods are indeed necessary. From factory methods to complicated metaprogrammed interfaces through ActiveRecord?s models custom query methods, class methods cannot be negated completely, yet should be used sparingly (see this excellent post by Code Climate for more on that).
This post does not concern itself with the ?class methods ? good or bad?? question; rather, it is a discussion between two stylistic approaches regarding how to notate those class methods when they are needed.
Style and Style Guides
The Ruby Style Guide indicates that the preferred way to define class methods is def self.method. It criticizes the more explicit def ClassName.method, but does subordinately support the more esoteric class << self syntax. Take a look at that section if you are unsure how all these actually look like.
Having a shared style and following an actual style guide within an organization is important. In a well-articulated write-up Sandi Metz claims that
[?] many stylistic choices are arbitrary, and purely a matter of personal preference. Choosing a style guide means building agreements in areas where we have strong differences of opinion about issues of little significance. It?s not style that matters, but sameness of style. (source)
That is a highly valid claim. Yet, it certainly is important to make the proper choices when picking up style. Similarly to fashion, code style reflects our credo as developers, our values and philosophy. In order to make an informed decision, it?s mandatory to understand the issue at stake well. We all have defined class methods many times, but do we really know how do they work?
The Singleton Class
To answer that question we will need a quick dive into the Ruby Object Model. In general, Ruby methods are stored in classes while data is stored in objects, which are instances of classes. That?s quite a common knowledge, so in order to challenge that, consider the following example:
an_array = [1, 5, 10]
If we try to run an_array.average we will get NoMethodError since neither Array nor its superclasses have an average method defined in them:
an_array.average# NoMethodError: undefined method `average’ for [1, 5, 10]:Array
We could monkey-patch Array and define an average method in it, but if we needed this method only for our an_array, we could also do this:
def an_array.average reduce(:+) / count.to_fend
Now this would work:
an_array.average # => 5.333333333333333
Yet executing the same method on another instance of Array would end up in NoMethodError again:
another_array = [1, 3, 7]another_array.average# => NoMethodError: undefined method `average’ for [1, 3, 7]:Array
That is because behind the scenes Ruby stored the average method in a special class that only an_array is pointing to ? its own singleton class:
an_array.singleton_class# => #<Class:#<Array:0x007fcf27848750>>an_array.singleton_methods# => [:average]
Every instance of every Ruby class has its own singleton class which is where its singleton methods are stored, such as the one we have just defined. (Well, almost every object; this is not true for Numeric objects.)When we call a method upon an object, its singleton class is the first place Ruby will look for that method, before the regular class and its ancestor chain.
Class Methods Are Singleton Methods
Since in Ruby classes are objects as well, class methods are merely methods defined on a specific instance of Class. Consider the following example:
We can see that theory in action easily:
Example.is_a? Object# => trueExample.class# => ClassExample.singleton_class => #<Class:Example>Example.instance_methods(false) => [:an_instance_method]Example.singleton_class.instance_methods(false) => [:a_class_method]
Calling instance_methods with the false argument simply excludes inherited methods from the methods lists (source).
Choices of Notation
Hurray, we now know exactly what class methods in Ruby are! We are ready to have an knowledgeable discussion about how to code them. As implied in the title of this post, I prefer the class << self approach over the def self.method one. Why?
I wish to define methods within the class they belong to. Using class << self demonstrates that approach clearly ? we are defining methods within the actual singleton class scope. When we usedef self.method, though, we are defining a method across scopes: we are present in the regular class scope, but we use Ruby?s ability to define methods upon specific instances from anywhere; self within a class definition is the Class instance we are working on (i.e. the class itself). Therefore, usingdef self.method is a leap to another scope, and this feels wrong to me.
Another reason to question the def self.method notation is the ability to define private and protected methods. Ruby does supply the private_class_method method in order to declare a class method as private; there is no equivalent for protected methods though. Also, for private class methods, you have to declare each method as such separately (i.e. you can?t use that simple private in the middle of your class, since that would apply to that class? instance methods). To sum up, class << self is actually clearer.
As mentioned in Sandi Metz?s post, style can bring up some emotionally-attached discussions between developers. Possible objections to theclass << self notation might be:
- ?It?s harder to find those class methods in larger classes that way? ? to which I admit, yes, it is. If you have that god-class which is 450 lines long, perhaps you should refactor it first and break it down into smaller classes but stick to def self.method meanwhile. If you have to scroll endlessly, it?s easy to miss out where does the scope change. But do refactor that class, yeah?
- ?It is less clear that way? ? that is just arbitrary, even uninformed. There is nothing clearer about def self.method. As demonstrated earlier, once you grasp the true meaning of it, def self.method is actually more vague as it mixes scopes. Understanding the theory behind the actions helps in explaining that.
- ?Who cares? Let?s just go with the style-guide? ? to which my response is that caring about the details is in the heart of much of our doings. Yes, this is not a major issue; def self.method is not even a code smell. Actually, that whole debate is on the verge of being incidental. Yet the learning process and the gained knowledge involved in understanding each choice is alone worth the discussion. Furthermore, I believe that the class << self notation echoes a better, more stable understanding of Ruby and Object Orientation in Ruby. Lastly, remember that style-guides may change or be altered (carefully, though!).
I hope you learned something new reading this post. If you have any remarks or questions about this topic, please use the comments! And if you found it interesting or useful, please support it by clapping it? .