I know you specifically asked for a way to do this without templates, but this was my first thought on how to make it work (and I confirmed it):

##############################
import  std.stdio   ,
        std.traits  ;

class Engine {

    int publicField ;

    void enumFields ( this Self ) ( bool heading = true ) {
        auto self = cast( Self ) this;
        if ( heading ) {
            writeln( "Engine prints:" );
        }
        foreach( base ; BaseClassesTuple!Self ) {
            static if ( is( base : Engine ) ) {
                ( cast( base ) self ).enumFields( false );
            }
        }
        foreach( ref field ; self.tupleof ) {
            writeln( '\t', field );
        }
    }

    protected string protectedField = "s" ;

    private bool privateField ;

}

class Some : Engine {

    int oneMoreField = 11;

    void enumFields2 () {
        writeln( "Some prints:" );
        foreach( field ; this.tupleof ) {
            writeln( '\t', field );
        }
    }

    protected string protectedField = "o";

}

void main () {
    auto objE = new Engine;
    auto objS = new Some;

    objE.enumFields();

    objS.publicField = 4;
    objS.enumFields();
    objS.enumFields2();

    ( cast( Engine ) objS ).enumFields();
}
##############################

The downside is that the reference you invoke enumFields() against must be of the lowest type to get all members, as that last line demonstrates. Beyond this, I don't believe there is any way for methods defined by Engine to see members of derived classes. The first alternative I could think of, is to use NVI (non-virtual interfaces).

##############################
import  std.stdio   ;

class Engine {

    int publicField ;

    final void enumFields () {
        writeln( this.classinfo.name, " prints:" );
        enumFieldsImpl();
    }

    protected string protectedField = "s" ;

    protected void enumFieldsImpl () {
        foreach ( field ; this.tupleof ) {
            writeln( '\t', field );
        }
    }

    private bool privateField ;

}

class Some : Engine {

    int oneMoreField = 11;

    protected override void enumFieldsImpl () {
        super.enumFieldsImpl();
        foreach ( field ; this.tupleof ) {
            writeln( '\t', field );
        }
    }

    protected string protectedField = "o";

}

void main () {
    auto objE = new Engine;
    auto objS = new Some;

    objE.enumFields();

    objS.publicField = 4;
    objS.enumFields();

    ( cast( Engine ) objS ).enumFields();
}
##############################

This works even in the last (previously degenerate) case, however it naturally results in code duplication. Depending on what your real scenario is, however, that may not be a severe issue.

-- Chris NS

Reply via email to