Ruby Class Inheritance

I just realize I have misunderstood the ruby “class methods” for quite a long time!

Here is a piece of code:

Instance Methods Inheritance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A
def foo
'foo'
end
end
class B < A
end
a = A.new
b = B.new
a.foo.should == 'foo'
b.foo.should == 'foo'

The previous piece of code demonstrated the typical inheritance mechanism in almost every Class-Object style OO language (There are a few exceptions, which are Prototype inheritance. Such as JavaScript, but it is also a miracle that whether Javascript is OO language XD).
In most common OO languages, this is what inheritance about! But in Ruby, things is not that easy! Great thanks to Ruby’s eigen-class (aka Singleton class or Metaclass)

In ruby, I just found that derived class not just inherits the instance methods but also the class methods! It is kind of surprise to me!

Class Methods Inheritance
1
2
3
4
5
6
7
8
9
10
11
class A
def self.bar
'bar'
end
end
class B < A
end
A.bar.should == 'bar'
B.bar.should == 'bar'

For most people who knows Java or C# or even C++, who won’t be surprised about A.bar.should == 'bar', but you might feel surprised about B.bar.should == 'bar' like I do.

To me, bar is declared on class A, B inherits A, than I can even call method declared on class A on class B! It is amazing!

Since in ruby, “class method” is actually the instance method of the eigen-class of the class. And def self.foo is just a syntax sugar. So we can rewrite the code as:

Rewriten Class Methods Inheritance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
end
class B < A
end
class << A
def bar
'bar'
end
end
A.bar.should == 'bar'
B.bar.should == 'bar'

If we call A’s eigen-class AA, and B’s eigen-class BB. Then we will found that BB.superclass == AA

BB and AA
1
2
3
4
5
6
7
8
9
10
11
class A; end
class B < A; end
AA = class << A; self; end
BB = class << B; self; end
B.superclass.should == A
BB.superclass.should == AA

And we know A is actually an instance of AA, and B is an instance of BB, so obviously on B we can call the instance methods defined on AA.
That’s the reason why class method in Ruby can be inherited!

But there are so inconsistency in Ruby, that AA is the superclass of BB, but you won’t be able to found AA in BB‘s ancestors! In fact, BB.ancestors might yield something similar to [Class, Module, Object, BasicObject, Kernel] if not any module is injected to Class, Module, Object

Inconsistency
1
2
3
4
5
6
7
8
9
10
11
12
class A; end
class B < A; end
AA = class << A; self; end
BB = class << B; self; end
BB.superclass.should == AA
BB.ancestors.should_not includes AA
# BB.ancestors == [Class, Module, Object, BasicObject, Kernel]

This design is wield to me, and kind of hard to understand, so for quite a long time, I don’t even know class methods in ruby can be inherited!
I drew a graph to show the relationship about the classes, in graph I use <class:A> to indicate the class is the eigen class of A. And the line with a empty triangle to represents the inheritance, and arrow line to represents the instantiation.
And this graph is not a complete one, I omitted some unimportant classes, and I uses the dot line to indicate that something is missing on the line.

Inheritance Hierarchy

Eigenclass in ruby

To me, “Eigenclass” is a weird name. Here is the definition of “Eigenclass” from wikipedia:

A hidden class associated with each specific instance of another class.

“Eigen” is a Dutch word, which means “own” or “one’s own”. So “Eigenclass” means the class that class owned by the instance itself.

To open the eigenclass of the object, Ruby provide the following way:

Open Eigenclass
1
2
3
4
5
6
7
foo = Foo.new
class << foo
# do something with the eigenclass of foo
end

Since the in most cases, the purpose that we open a eigenclass is to define singleton methods on specific object. So Ruby provide an easy way to define the singleton method on specific instance:

Shorten saying
1
2
3
4
5
6
7
foo = Foo.new
def foo.some_method
# do something
end

Since “static method” or “class method” is actually the singleton method of a specific class. So this statement is usually used to declare the “class method”.

Besides this simpler statment, we also can open the eigenclass of the class to achieve the same result.
We can write this:

Open eigenclass of the class
1
2
3
4
5
6
7
8
9
10
11
class Foo
class << self
# define class methods
end
# define instance methods
end

Since we’re in the class block, so the “self” indicates the Foo class instance. So we can use class << self; end to open the eigenclass of the class.