I've been in multiple discussions lately about the problems with subclassing Ruby's base types.
The main problem is that Ruby sometimes takes shortcuts with the base types, for performance reasons. This can cause them to behave odd. For example, have a look at this subclass:
class MyString < String
def initialize(*)
super
puts "Building MyString: #{inspect}"
end
end
result = MyString.new("CATG").tr(MyString.new("T"), MyString.new("U"))
p result.class
p result
That outputs the following
Building MyString: "CATG"
Building MyString: "T"
Building MyString: "U"
MyString
"CAUG"
Notice that the constructor was not called for the fourth MyString
returned as a result from the tr()
call.
Reopening String
itself can lead to even more surprising behavior:
class String
alias_method :string_initialize, :initialize
def initialize(*args, &block)
string_initialize(*args, &block)
puts "Building MyString: #{inspect}"
end
end
result = String.new("CATG").tr("T", "U")
p result.class
p result
This works even less often:
Building MyString: "CATG"
String
"CAUG"
You can see that it only works with the explicit call. Ruby's syntactic shortcuts just bypass the constructor altogether.
My opinion is that these inconsistencies mean that this tactic is just best avoided.