Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

question about overriding initialize method

Tags:

ruby

I encountered a strange question about override initialize message of BigDecimal.

class Test1 < String
  def initialize(a, b)
    puts a
    puts b
  end
end

require '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?

like image 403
Richard Huang Avatar asked Nov 30 '09 08:11

Richard Huang


3 Answers

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.

like image 159
MBO Avatar answered Oct 10 '22 10:10

MBO


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.

like image 2
nas Avatar answered Oct 10 '22 10:10

nas


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.

like image 1
Mike Woodhouse Avatar answered Oct 10 '22 10:10

Mike Woodhouse