2

As mentioned in an answer to a previous question, B < A is the easiest way to determine whether a class is a subclass of another. However, this appears to fail in Ruby 1.8 (also REE 1.8) when B is a singleton class (i.e., eigenclass). To illustrate:

class A; end
class B < A; end

b = B.new

B.ancestors                         # => [B, A, Object, Kernel] (also BasicObject in 1.9)
(class << b; self; end).ancestors   # => [B, A, Object, Kernel] (also BasicObject in 1.9)

B < A                               # => true
(class << b; self; end) < A         # => true in 1.9; false in 1.8

As you can see, even though A is listed as an ancestor of the singleton class (class << b; self; end), it returns false when you check whether its a subclass of A in Ruby 1.8 (but correctly returns true in 1.9). Following the #superclass chain appears to show why this is the case:

B.superclass
  # => A

(class << b; self; end).superclass
  # => B in 1.9
  # => singleton class of B in 1.8

(class << b; self; end).superclass.superclass
  # => A in 1.9
  # => singleton class of Class in 1.8

Does anyone know whether this is a bug in 1.8 that happened to be fixed in 1.9 or perhaps expected behavior that was purposefully changed in 1.9? I've tried finding mention or documentation of this issue elsewhere but haven't been able to find anything.

And because of this issue, does anyone know what's the best way to check that the singleton class is a subclass of A in Ruby 1.8? I've been doing (class << b; self; end).ancestors.include?(A) as a workaround, though it's not technically "correct" since the list of ancestors also contains included modules.

Community
  • 1
  • 1
Claw
  • 767
  • 8
  • 22

1 Answers1

1

I would suggest:

class Object; def metaclass; class << self; self; end; end; end

class A; end
class B < A; end

b = B.new

b.metaclass < A.metaclass || b.metaclass < A

Tested in Ruby 1.8, 1.9, and 2.0.

Jacob Lukas
  • 689
  • 6
  • 14