question about overriding initialize method
I encountered a strange question about override initialize message of BigDecimal.
class Test1 < String
def initialize(a, b)
puts a
puts b
end
end
requ开发者_如何转开发ire 'bigdecimal'
class Test2 < BigDecimal
def initialize(a, b)
puts a
puts b
end
end
>> Test1.new('a', 'b')
a
b
>> Test2.new('a', 'b')
TypeError: wrong argument type String (expected Fixnum)
from (irb):17:in `new'
from (irb):17
Why I can override the initialize message of String, but not of BigDecimal?
When you look into sources of Ruby classes, you'll see that the String
class defines method String#initialize
, which is called after String#new
(inherited from Object
) for allocating a new instance. You don't call String#initialize
(or #super
) in your new instance so you got ""
when you inspect the newly created object.
BigDecimal
defines method Bigdecimal#new
, which allocates its own object. Object creation consists of two parts - allocating space for new object and initializing it. You only defined initializing new object, so you stay with default allocating space for object. If you want to override it, you should define #new
in your new class and call BigDecimal
's #new
with proper arguments.
Hope that clarifies a little what happen in your example.
Yes, BigDecimal implements the new class method and if you override that in your test2 class then you can write your Test2 initialize method in any way you want, for e.g.
class Test2 < BigDecimal
def self.new(a)
puts a
end
def initialize(a)
puts a
end
end
Test2.new("a")
The class method new is the object constructor which sets up the object state and allocates memory once the object is initialized by using the initialize method.
But generally we don't implement the new method as it is the default constructor method provided by ruby although it can be overridden by redefining it in your class if there is a strong reason for doing that and that is what BigDecimal has done.
It looks like there's some type checking occurring in BigDecimal.new()
, which is getting upset before your overridden initialize
is reached. See point 19 in this list
It's not often an issue (I remembered something but still had to look it up) but there's a new
class method that, if I recall correctly, actually creates the object and then calls initialize
.
Overriding new
on the class, thus:
class Test2 < BigDecimal
def Test2.new(a, b)
puts a
puts b
end
end
Test2.new('42', 'banana')
gives the hoped-for answer.
精彩评论