Ruby's Class.allocate
Today I’m going to discuss the little-known ruby method, Class.allocate.
What is #allocate?
In these situations, so that I don’t miss any details - I like to turn to Ruby’s source, which as of 1.9.3 is:
Cool - that’s easy enough of a translation:
So #new is just an allocation followed by a call to initialize. Ruby exposes the allocate method to us decoupled from #initialize!! If you’re an Objective-C developer, you may be saying “haha, us too!”, and you’d be totally right:
[[Something alloc] init];
is commonly used instead of:
[Something new];
That's great, why do I want it?
One of the reasons that Objective-C programmers prefer [[Something alloc] init] is that it makes calling custom initializers much easier. So instead of always calling init, you may want to initWithConnection. We can use it very similarly in Ruby (and ActiveRecord does just that internally).
Imagine we have a “Data” class that is used for just storing some data:
And then some day we want to be able to initialize an instance of Data already populated.
We have a few options. The most common is probably to add a parameter to the initializer:
This works really well, but we’ve modified the public interface here in order to allow for this edge case. It’s easy to imagine a time 20 options down the line where our initializer gets pretty ugly.
Another option is to allow setting of data by any member:
Again - this works, but what about the fact that we’re (1) exposing data to be changed at any point in a classes’ life, and (2) wasting time initializing data to a value inside of #initialize that we will never use.
The way we’d accomplish this with allocate is more factory-like:
That way, people can continue to use #new how they do, and when they want to initialize one with pre-populated data they can use #initialize_stored with no object overhead.