You Can’t Subclass Integers in Ruby

This post is mainly just an excuse to test a Gist plugin for WordPress.

Occasionally, you might think it would be handy to subclass Numeric types such as Integer. For instance, you might want to create a constrained integer which can only have certain values.

Ruby isn’t quite turtles all the way down, though: Numerics in Ruby are immediates, meaning that they don’t represent a heap-allocated object. Since you can’t allocate them, you can’t create a subclass and allocate instances of the subclass:

[gist id=1124430]

9 comments

  1. Another interesting artifact of integers in ruby:

    irb(main):001:0> (-2..2).map {|i| i.object_id }
    => [-3, -1, 1, 3, 5]
    irb(main):002:0> true.object_id
    => 2
    irb(main):003:0> false.object_id
    => 0
    irb(main):004:0> nil.object_id
    => 4
    
  2. Another interesting artifact of integers in ruby:

    irb(main):001:0> (-2..2).map {|i| i.object_id }
    => [-3, -1, 1, 3, 5]
    irb(main):002:0> true.object_id
    => 2
    irb(main):003:0> false.object_id
    => 0
    irb(main):004:0> nil.object_id
    => 4
    
      1. This is because (at least in MRI and YARV) the least significant bit of the object id says whether it’s an immediate Fixnum or not (odd object id → it’s a Fixnum, even object id → it’s some other object). This is also the reason why Fixnums on 32-bit systems are limited to 2^30-1 (of the 32 bits, one is used for the Fixnum/non-Fixnum choice, the other for the Fixnum’s sign).

        More fun (with false/true/nil/undef and symbols, as well as object_id ↔ C’s VALUE differences) at gc.c’s rb_obj_id(): https://github.com/ruby/ruby/blob/ruby_1_9_2/gc.c#L2834

        1. In Ruby 2.0.0-p247:

          pry(main)> (-2..2).map {|i| i.object_id }
          => [-3, -1, 1, 3, 5]
          pry(main)> true.object_id
          => 20
          pry(main)> false.object_id
          => 0
          pry(main)> nil.object_id
          => 8

Leave a Reply to nevans Cancel reply

Your email address will not be published. Required fields are marked *