Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I inherit from Rational (or any class with no constructor)?

I can easily inherit from, say, String for example, like this:

class MyString < String
  def stuff
    self + ' and stuff'
  end
end

# This works:
MyString.new('things').stuff # => 'things and stuff'

But how can I inherit from Rational, which has no constructor? For example:

def MyRat < Rational
  def inc
    self + 1
  end
end

# I have tried to initialize like this:
MyRat.new(10).inc # => NoMethodError: undefined method `new' for MyRat:Class
MyRat(10).inc # => NoMethodError: undefined method `MyRat' for main:Object
MyRat.send(:initialize, 10).inc  # => TypeError: already initialized class
# ???
# None of it works!

I can't find a way to initialize my new class.

like image 771
tckmn Avatar asked Dec 18 '13 19:12

tckmn


1 Answers

You can define your own object to be a proxy around Rational.

class MyRat < BasicObject
  def initialize(value)
    @rational = Rational(value)
  end

  def inc
    @rational + 1
  end

  def method_missing(name, *args, &block)
    @rational.send(name, *args, &block)
  end
end

Methods defined in your class will be used, otherwise the class will delegate to the rational instance.

r = MyRat.new(10)

# MyRat#inc is used
r.inc
# => (11/1) 

# to_int delegates to Rational
r.to_int
# => 10 

A partial explanation of because Numeric has no initialize is available in this thread

Looking at the C code, I see that new() exists in Numeric and Float, but it is specifically removed: rb_cInteger = rb_define_class("Integer", rb_cNumeric); rb_undef_alloc_func(rb_cInteger); rb_undef_method(CLASS_OF(rb_cInteger), "new");

#....and for floats..
rb_undef_alloc_func(rb_cFloat);
rb_undef_method(CLASS_OF(rb_cFloat), "new");

The ruby source code contains no explanation for the removal of new. That's why I'm wondering what the reasoning behind this was. It does not seem to be technical limitation in the ruby interpreter. Currently, it does not make much sense to me.

and the reason is because

It's an internal optimization. Fixnums do not have to be created and they never have to be GC'ed. This goes a long way to make math faster than it would be with ordinary objects (at least for Fixnums).

Additional suggestions and alternatives are explained in this article The Complete Numeric Class.

like image 198
Simone Carletti Avatar answered Oct 06 '22 00:10

Simone Carletti