# Class#descendants?

**URL:** <https://www.ruby-forum.com/t/class-descendants/173660>\
**Category:** Ruby\
**Created:** [August 12, 2009, 9:30pm UTC](https://www.ruby-forum.com/t/class-descendants/173660 "2009-08-12T21:30:36Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 9:30pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/1 "2009-08-12T21:30:36Z")

</div>

Ruby can do Class#ancestors but not Class#descendants.

I found this: [Class#descendants – qerub.se](http://termos.vemod.net/class-descendants)

But it only works after you define a new inheritance. Is there a way to  
find descendants of a class that is already in place? For example:

Numeric.descendants  
=\> [Integer, Float, Complex]

Thank you.

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 9:40pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/2 "2009-08-12T21:40:14Z")

</div>

Jason L. wrote:

> Thank you.  
> irb(main):001:0\> ObjectSpace.each\_object(Class) {|cl| p cl if cl \<  
> Numeric}  
> Bignum  
> Float  
> Fixnum  
> Integer

But keep in mind: it’s inefficient (so cache if you can), and it may not  
be standard across rubies (jruby may not have it IIRC). It’s useful for  
interactive poking around though.

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 9:50pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/3 "2009-08-12T21:50:46Z")

</div>

On 12.08.2009 21:30, Jason L. wrote:

> Ruby can do Class#ancestors but not Class#descendants.
> 
> I found this: [Class#descendants – qerub.se](http://termos.vemod.net/class-descendants)
> 
> But it only works after you define a new inheritance. Is there a way to  
> find descendants of a class that is already in place? For example:
> 
> Numeric.descendants  
> =\> [Integer, Float, Complex]

Let me first state that I believe this is intentional: while sub classes  
need knowledge of their parent classes the opposite is not true. In  
fact, that would create a kind of circular dependency.

Having said that, this is what you could do

require ‘set’  
h = Hash.new {|h,k| h[k] = Set.new}

ObjectSpace.each\_object(Class) do |cl|  
cl.superclass.ancestors.each {|scl| h[scl] \<\< cl}  
end

p h[String]

You should keep in mind though that this is by no means static. New  
classes can come in existence at any time.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 9:46pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/4 "2009-08-12T21:46:39Z")

</div>

Joel VanderWerf wrote:

> irb(main):001:0\> ObjectSpace.each\_object(Class) {|cl| p cl if cl \<  
> Numeric}

Thank you. Why does it return 387 after I do this in IRB?

like this:  
irb(main):069:0\> ObjectSpace.each\_object(Class) {|cl| p cl if cl \< Date}  
DateTime  
=\> 387

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 10:09pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/5 "2009-08-12T22:09:30Z")

</div>

Jason L. wrote:

> Joel VanderWerf wrote:
> 
> > irb(main):001:0\> ObjectSpace.each\_object(Class) {|cl| p cl if cl \<  
> > Numeric}
> 
> Thank you. Why does it return 387 after I do this in IRB?
> 
> like this:  
> irb(main):069:0\> ObjectSpace.each\_object(Class) {|cl| p cl if cl \< Date}  
> DateTime  
> =\> 387

It’s the number of instances of Class (since that was the argument). So  
another example is:

irb(main):002:0\> ObjectSpace.each\_object(String) {}  
=\> 4613

(Yep, the empty block is necessary.)

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 9:54pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/6 "2009-08-12T21:54:49Z")

</div>

Robert K. wrote:

> You should keep in mind though that this is by no means static. New  
> classes can come in existence at any time.

This is great. Thank you.

I really just want to play around for educational purposes to get a feel  
for the Ruby class hierarchy.

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 9:57pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/7 "2009-08-12T21:57:57Z")

</div>

Robert K. wrote:

> ObjectSpace.each\_object(Class) do |cl|  
> cl.superclass.ancestors.each {|scl| h[scl] \<\< cl}  
> end

I’m getting this error:

irb(main):085:0\> ObjectSpace.each\_object(Class) do |cl|  
irb(main):086:1\* cl.superclass.ancestors.each {|scl| h[scl] \<\< cl}  
irb(main):087:1\> end  
NoMethodError: undefined method `ancestors' for nil:NilClass from (irb):86 from (irb):85:in`each\_object’  
from (irb):85  
from :0

Is there a reason superclass is returning nil on cl?

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 10:55pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/8 "2009-08-12T22:55:45Z")

</div>

On 12.08.2009 21:57, Jason L. wrote:

> irb(main):087:1\> end  
> NoMethodError: undefined method `ancestors' for nil:NilClass from (irb):86 from (irb):85:in`each\_object’  
> from (irb):85  
> from :0
> 
> Is there a reason superclass is returning nil on cl?

Oops, I inserted “superclass” after doing the test. This is likely the  
case of Object. If you remove it it works as well. Sorry, for the  
hassle.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 13, 2009, 12:05am UTC](https://www.ruby-forum.com/t/class-descendants/173660/9 "2009-08-13T00:05:59Z")

</div>

Tony A. wrote:

> For what it’s worth, here’s my implementation, which doesn’t use  
> ObjectSpace. It’s a bit less trivial and I wonder if it could be made  
> better:
> 
> [gist:166800 · GitHub](http://gist.github.com/166800)
> 
> Workarounds for ActiveSupport included, yay!

Not all classes are constants…

my\_numbers = Class.new(Numeric)

p Numeric.descendants  
a = []  
ObjectSpace.each\_object(Class) {|cl| a \<\< cl if cl \<= Numeric}  
p a

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 13, 2009, 2:54am UTC](https://www.ruby-forum.com/t/class-descendants/173660/10 "2009-08-13T02:54:33Z")

</div>

Oi, good catch.

So the question remains… can this be done without ObjectSpace?

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [August 12, 2009, 11:53pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/11 "2009-08-12T23:53:41Z")

</div>

On Wed, Aug 12, 2009 at 1:39 PM, Joel VanderWerf  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)wrote:

> irb(main):001:0\> ObjectSpace.each\_object(Class) {|cl| p cl if cl \< Numeric}

For what it’s worth, here’s my implementation, which doesn’t use  
ObjectSpace. It’s a bit less trivial and I wonder if it could be made  
better:

> <https://gist.github.com/tarcieri/166800>

Workarounds for ActiveSupport included, yay!

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [September 3, 2009, 7:19am UTC](https://www.ruby-forum.com/t/class-descendants/173660/12 "2009-09-03T07:19:09Z")

</div>

On Wed, Aug 12, 2009 at 2:39 PM, Joel  
VanderWerf[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> irb(main):001:0\> ObjectSpace.each\_object(Class) {|cl| p cl if cl \< Numeric}  
> Bignum  
> Float  
> Fixnum  
> Integer
> 
> But keep in mind: it’s inefficient (so cache if you can), and it may not be  
> standard across rubies (jruby may not have it IIRC). It’s useful for  
> interactive poking around though.

This is actually the one each\_object case we do support with general  
ObjectSpace support turned off, since we maintain a weak reference  
from parent to child classes (so we just walk everything from Object  
down; it’s for our method-caching logic).

- Charlie

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [September 3, 2009, 6:20pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/13 "2009-09-03T18:20:12Z")

</div>

On Thu, Sep 3, 2009 at 9:59 AM, Charles Oliver N.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)wrote:

> ~/projects/jruby âž” jruby -rjruby/core\_ext -e “p Numeric.subclasses(true)”  
> [Precision, Precision, Integer, Bignum, Fixnum, Float]
> 
> It doesn’t filter out the “included wrapper” from included modules,  
> but it’s there. I suggested it as an official addition to Ruby, but  
> nobody seemed interested in the idea at the time.

My two cents: I would love to see this as an official addition to Ruby.

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [September 3, 2009, 5:59pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/14 "2009-09-03T17:59:42Z")

</div>

On Thu, Sep 3, 2009 at 12:16 AM, Charles Oliver  
Nutter[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> This is actually the one each\_object case we do support with general  
> ObjectSpace support turned off, since we maintain a weak reference  
> from parent to child classes (so we just walk everything from Object  
> down; it’s for our method-caching logic).

Oh, I suppose I should also mention this:

~/projects/jruby âž” jruby -rjruby/core\_ext -e “p  
Numeric.subclasses(true)”  
[Precision, Precision, Integer, Bignum, Fixnum, Float]

It doesn’t filter out the “included wrapper” from included modules,  
but it’s there. I suggested it as an official addition to Ruby, but  
nobody seemed interested in the idea at the time.

- Charlie

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [September 3, 2009, 9:30pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/15 "2009-09-03T21:30:12Z")

</div>

Tony A. wrote:

> Oi, good catch.
> 
> So the question remains… can this be done without ObjectSpace?

Yes, if you’re willing to accept the monkeypatch on Class:

[http://pastie.org/604847](http://pastie.org/604847)

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [September 3, 2009, 10:13pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/16 "2009-09-03T22:13:16Z")

</div>

On Thu, Sep 3, 2009 at 1:30 PM, Duck Typist  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)wrote:

> Yes, if you’re willing to accept the monkeypatch on Class:
> 
> [http://pastie.org/604847](http://pastie.org/604847)

But this covers even fewer cases than the non-ObjectSpace example I gave  
earlier:

> <https://gist.github.com/tarcieri/166800>

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [September 3, 2009, 10:30pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/17 "2009-09-03T22:30:12Z")

</div>

Tony A. wrote:

> On Thu, Sep 3, 2009 at 1:30 PM, Duck Typist  
> [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)wrote:
> 
> > Yes, if you’re willing to accept the monkeypatch on Class:
> > 
> > [http://pastie.org/604847](http://pastie.org/604847)
> 
> But this covers even fewer cases than the non-ObjectSpace example I gave  
> earlier:
> 
> [gist:166800 · GitHub](http://gist.github.com/166800)

Sorry, my bad. Guess so.

---

<div class="post-metadata">

**Author:** ![leveille](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/a88e57/32.png) [@leveille](https://www.ruby-forum.com/u/leveille)\
**Post date:** [September 3, 2009, 10:20pm UTC](https://www.ruby-forum.com/t/class-descendants/173660/18 "2009-09-03T22:20:53Z")

</div>

On Thu, Sep 3, 2009 at 3:30 PM, Duck  
Typist[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Tony A. wrote:
> 
> > Oi, good catch.
> > 
> > So the question remains… can this be done without ObjectSpace?
> 
> Yes, if you’re willing to accept the monkeypatch on Class:
> 
> [http://pastie.org/604847](http://pastie.org/604847)

Try that code with p Object.descendants

Your inherited hook is too late.

–  
Rick DeNatale

Blog: [http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)  
Twitter: [http://twitter.com/RickDeNatale](http://twitter.com/RickDeNatale)  
WWR: [http://www.workingwithrails.com/person/9021-rick-denatale](http://www.workingwithrails.com/person/9021-rick-denatale)  
LinkedIn: [http://www.linkedin.com/in/rickdenatale](http://www.linkedin.com/in/rickdenatale)
