Class Methods
In my last post I wrote that providing a home for class methods was the raison d’être of the Metaclass. So why go through all the trouble? What are class methods good for? Four uses worth exploring are Object Creation, Annotations, DSL’s, and removal of structural duplication
This post is about Ruby class methods and not Ruby static methods. There is a good reason for this. There are no static methods in Ruby.
In Java and C# “static method” and “class method” are synonyms, with “static” indicating that the methods are statically bound. What does it mean for a method to be statically bound? Consider a normal (non-static) instance method in Java. Client code that consumes the method doesn’t know at compile time what method body will be associated with that usage. It may be the instance method defined on the class, but it may just as well be an overridden version of the method defined in a subclass. The method implementation must be “dynamically bound” to the invocation at runtime. The compiler doesn’t have this issue with class methods, as in Java and C# class methods cannot be overridden. Classes methods in Java and C# are not invoked on class instance, but are rather scoped to the class name. As class method references can only resolve to one location, the compiler can “bind” the reference once at compile time “statically”. Classes methods in Ruby are normal instance methods stored on the class’s Metaclass. Even if Ruby were a compiled language, there would be no way to know at compile time which implementation of a method would eventually be responding to a message passed to a class object at runtime.
In any OO language, the most common use of class methods is for object creation. Every Ruby programmer is familiar with the primary object creation class method, new. Most programmers have also had cause to define alternative class methods for instantiating an object. In “Effective Java”, Joshua Bloch enumerates the advantages of this sort of factory method. These advantages are wholly applicable to Ruby.
Class methods have names
Java requires all method signatures to be unique. Suppose a Java programmer wants to allow the instantiation of an object in two different ways. Both instantiation methods rely on a boolean and an int parameter. One way to solve this is to define two constructors…
This is valid Java, but it’s just a wee bit hackish to be overloading methods based on the order of their parameters. Consumers of the class must infer the difference between the two constructors from the parameter names or a reading of the source. In Ruby this problem is more acute, firstly because of duck typing, and secondly because Ruby has no facilities for method overloading. For example, consider a Ruby class defined as…
The second definition of initialize completely replaces the first definition. Hacked up solutions to this type of problem aren’t relegated to the Java world. In fact, duck typing allows for some horribly creative solutions in Ruby. WARNING! Don’t do this…
or this…
or this…
Instead strongly prefer…
For an in the wild example of a factory class method in Ruby, look no further than ActiveRecord:Base.create
Class methods don’t have to return a new object
Sending the new message to a class will always cause the interpreter to create a new instance of the class. This occurs in rb_class_new_instance, the function bound to the new method of Object.
rb_class_new_instance calls rb_obj_alloc to allocate a new object which is handed off to the initialize method by rb_obj_call_init. As an interesting side note, notice that you can avoid having the initialize methods called by instantiating objects by calling SomeClass.allocate which returns the return value of rb_obj_alloc.
Sometimes a new object is not required, but rather a reference to an instance from a pool of existing objects. Database connections are one common example. Class methods are an excellent solution to the problem of how to provide access to the instance pool. When the available pool of instances is limited to one object, this solution is an implementation of the Singleton Pattern. “Singleton” here refers to the OO pattern documented in Design Patterns by Gang-Of-Four, not the Ruby specific Singleton class.
The Ruby Standard library includes a Singleton module to take the work out of implementing this pattern. The source includes extensive documentation on the implementation, so I won’t cover it here. Suffice to say that the module adds a class method, instance to the including class.
Why have this module at all? The Ruby language already provides a facility for creating objects with only one instance, classes. Why not define a singleton as a class…
The interpreter guarantees that there will only ever be one instance of Foo’s Metaclass, the Foo class itself. The existence of metaclasses means this question is applicable to Smalltalk as well. In “The Design Patterns Smalltalk Companion” by Sherman R. Alpert, Kyle Brown, and Bobby Wolf, two cases are made against implementing the Singleton Pattern with class methods. The first is conceptual. Classes should not be domain objects, their role is to allow for accessing and instantiating domain objects. Defining domain logic directly in classes is a perversion of this intent. The second argument is pragmatic. If a requirement is introduced that requires the usage of multiple instances of the formally singleton object, the refactoring away from class method calls is more laborious then a traditional Singleton pattern implementation. Although ‘The Design Patterns Smalltalk Companion” is a valuable read for Ruby programmers, in this case I don’t find the arguments particularly compelling . Class methods probably are the simplest thing that could possible work when Singleton Pattern like functionality is needed.
Class methods can return subclasses
A classic usage of factory methods is to return a subclass of the class receiving the message based on an input parameter. This is good encapsulation, as the consumer of the class does not need to know the details of which subclasses exist and which is appropriate for it’s needs.
If one is fortunate enough to have useful conventions in place, a bit a metaprogramming can make this usage particularly powerful. For example instead of …
one could implement by_nationality as…
Not only is this implementation more succinct, it extensible to handle any Pirate nationality that follows the convention. Keep in mind that classes aren’t the only place to store behavior. Class methods might return a new instance of the class with modules mixed in…
Perhaps even more powerful, a class method might alter the Singleton class of an instance before retuning the object. This is essentially subclassing on the fly. Suppose Pirate’s have fighting behavior. A class method could be created to return a pirate with a customized fighting style…
Even further out on the metaprogramming ledge, the consumer could define the fighting style directly…
This last example, while interesting, doesn’t strike me as good style. The consumer knowing both that it needs a Pirate to fight, and the implementation details of that fighting style seems like an awful lot for the consumer to know.
That covers using class methods for object creation. I’ll be covering class methods usage for annotations, DSL’s, and removal of structural duplication in the next post(s). As always thanks for reading. I’m always happy to get your feedback, inquiries, corrections, and criticism.
Thanks to John Hume for contributing his insight and expertise to this post.