There have been numerous implementations of the method Class.descendants by various gems. However, I can't help but think that this ability should be included in the Ruby language itself. Especially since Ruby already offers the counterpart method Class.ancestors.
Would it possible to add a
descendants class method?
#1 [ruby-core:85077] Updated by shevegen (Robert A. Heiler) 10 months ago
I do not know if it was suggested before, but it could be discussed
at the ruby developer meeting perhaps (unless it was already rejected).
I think it may be symmetrical to .ancestors too.
To complete your suggestion, could you describe at the least one
use case when this functionality may be useful? The ruby core team
said in the past that they prefer solving real problems - not that
I am saying that you do not have any real problem, mind you; just
so that it can be included here (you mentioned gems that do so but
in the above suggestion there are not yet any specific names; may
also help so that others can have a look as well). But anyway,
these are just my suggestions - feel free to ignore them if you
want to. :)
#2 [ruby-core:85083] Updated by ridiculous (Ryan Buckley) 10 months ago
Thanks for the reply, shevegen, those are helpful questions :)
The gems I've seen implement this are active-support and dry-rb, with other people checking ObjectSpace to get the list (which can be very slow for large apps).
The most common use case for this that I've seen, is implementing the Chain of Responsibility pattern. In this case, we want to find a "handler" class for a certain type of input, from a list of registered classes. Instead of configuring the handlers as a static array, it's easier and more flexible to be able to lookup the list dynamically at runtime. The lookup is done by finding all subclasses of a certain base class. Because there is no fast and out-of-the-box way to do this, I've historically opted for the configured list approach.
#4 [ruby-core:85117] Updated by Hanmac (Hans Mackowiak) 10 months ago
"Class#inherited hook" works not for core classes because they are defined before you can define the hook
also should that show only named classes or anonymous somehow too?
ridiculous (Ryan Buckley): i often see a register method where you register your new class onto a name/key to that handler service
#5 Updated by ridiculous (Ryan Buckley) 10 months ago
@Hanmac yeah, registering with a method or a static list is common practice. But I feel like Ruby can do better.
For many cases, it's possible to track them with the inherited hook, @Erogon. But for something so fundamental, why not include it in the language?
I'm interested in the history, as I see it was presented and even tentatively scheduled for version 2.2 (https://bugs.ruby-lang.org/issues/9779), wondering what happened?
#6 [ruby-core:85125] Updated by Eregon (Benoit Daloze) 10 months ago
I think one part of the discussion was that this features requires classes to explicitly track their subclasses (which is a memory overhead, and it must be a list of weak references to avoid leaking subclasses).
I think MRI now tracks subclasses but didn't use to.
FWIW TruffleRuby currently doesn't need to track subclasses (But doing it would probably not be a very big overhead, we already need to track constants, class vars and methods in each Class so Class objects are anyway not so lightweight).