Get symbols (and/or UDAs) of subclass from superclass

Simen Kjærås simen.kjaras at gmail.com
Sun Mar 15 21:28:45 UTC 2020


On Sunday, 15 March 2020 at 20:18:03 UTC, James Blachly wrote:
> I would like to programmatically retrieve members of a subclass 
> to create a self-documenting interface. I am afraid that my 
> approach is not possible due to need for compile time __traits 
> / std.traits, and runtime typeinfo. My proposed approach is as 
> follows:
>
> class Base
> {
>     string whatever;
>
>     string toString()
>     {
>         // loop over __traits(allMembers, typeof(this)) or 
> getSymbolsByUDA, etc.
>     }
> }
>
> /// There may be a dozen Derived classes
> class Derived1 : Base
> {
>     @Config("a name", "a description")
>     float probability;
> }
> class Derived2 : Base
> {
>     @Config("another", "more description")
>     int replicates;
> }
> ...

There's no built-in way to do this - toString() doesn't know what 
derived classes exist, and more could be added from other modules 
and even dynamically loaded libraries. Now, there are ways to do 
something somewhat like it. I would suggest creating an abstract 
method in the base class, that derived class would have to 
override, and use a template this argument to get the correct 
type for __traits(allMembers) to operate on:

class Base {
     override string toString() {
         return toStringImpl();
     }
     abstract string toStringImpl();
     string toStringBase(this That)() {
         // foreach (e; __traits(allMembers, That) {...}
     }
}

class Derived : Base {
     override string toStringImpl() {
         return this.toStringBase();
     }
}

Since toStringImpl will always call toStringBase, this could 
perhaps better be modeled with a template mixin:

mixin template DerivedToString() {
     override string toStringImpl() {
         return this.toStringBase();
     }
}

class Derived2 : Base {
     mixin DerivedToString!();
}

This way, you can have all the logic of toString in the base 
class, and the only thing a subclass will have to include is one 
line for the mixin. In addition, since toStringImpl is abstract, 
the implementer of a subclass will get a compile-time error if he 
or she forgets to do either the mixin or override toStringImpl 
themselves.

--
   Simen


More information about the Digitalmars-d-learn mailing list