Here’s a little problem I ran into in some old code of mine.
Sometimes we’ve got methods where we want to return a new instance of the same class.
It’s tempting to write the following code:
>> class A >> def a_whole_new_me >> A.new >> end >> end
Sure enough, that seems to work:
>> a = A.new >> a.class => A >> a.a_whole_new_me.class => A
So what’s wrong with it? We forgot about subclasses!
>> class B < A; end >> b = B.new >> b.class => B >> b.a_whole_new_me.class => A
If we’re expecting a copy of B and get A, this is certainly going to cause trouble, but the scary part is it might not right away (since B usually has all of A’s methods, but not necessarily the other way around)
Luckily, this is easy to fix, just use self.class
>> class A >> def a_whole_new_me >> self.class.new >> end >> end >> a = A.new >> a.class => A >> a.a_whole_new_me.class => A >> class B < A; end >> b = B.new >> b.class => B >> b.a_whole_new_me.class => B
This practice is usually a good idea whenever we want to refer to our class object. Rather than making things rigid, if you use self.class when possible, your code will be easier to extend and behave better in general. Of course, your mileage may vary depending on your task.


Indeed, this was recently addressed in the Pathname library. Good post. :)
Better yet, don't override the default #dup() method with a broken version. The #dup() method given above doesn't create a copy, it just creates a new blank instance.
The point about preferring "self" to an explicit classname is well taken, however. Definitely a best practice.
Well, it's a blank class.
So I don't think you'll find any difference. :)
I agree with Daniel. #dup should not be overriden. Instead, the method #initialize_copy, which is called by #dup, is the method to override to add your custom behavior.
Sorry, I meant "I agree with Avdi". The fact that the name of the author is below his comment is confusing.
#dup should not be overriden. Instead, the method #initialize_copy, which is called by #dup, is the method to override to add your custom behavior.
Good point, now that I look at the docs for that, I'll change the example to show a slightly different use case, but avoid this 'bad advice' mixing in with the good advice. :)