www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - An experimental reflection library

reply s31552 mail.ecc.u-tokyo.ac.jp writes:
I implemented a reflection library in D experimentally. Because now
DMD compiler does not support reflection, my implementation is not
smart.

If you want to use my reflection library, you should prepare a file
which contains symbol table using /MAP linker option. (or nm(1)
command on Unix). The library read the symbol table from the file and
demangle symbols. Since the symbols of D language has type
infomations, the symbol table is enough to implement reflection.

You can download the library here:
http://user.ecc.u-tokyo.ac.jp/~s31552/wp/d/reflection.tar.bz2

The file contains four files, reflection.d is the main library code,
test_reflection.d is a test code, and build_*.sh are build
scripts. The library supports both DMD and GDC. I check this library
with DMD&Windows, DMD&Linux, GDC&Linux, GDC&MacOSX. Please note that
the library has a lot of todos to simulate real reflection and the
library will be no use if DMD supports reflection.

A sample code of my library is the following:

import reflection;

class Test {
    void test_func1() { std.stream.stdout.writeLine("func1"); }
    void test_func2() { std.stream.stdout.writeLine("func2"); }
    void test_func3() { std.stream.stdout.writeLine("func3"); }
    int test_ignore1() { std.stream.stdout.writeLine("error"); return 0; }
    void test_ignore2(int i) { std.stream.stdout.writeLine("error"); }
    void ignore() { std.stream.stdout.writeLine("error"); }
}

int main(char[][] args) {
    Reflection.init(args[1]);

    Test test = new Test();
    Class c = Class.forName("test_reflection.Test");
    if (c !== null) {
        foreach (Method m; c.methods) {
            std.stream.stdout.writeLine("found: " ~ m.name);
            if (m.name.length >= 4 && m.name[0..4] == "test" &&
                m.type.func.ret.builtin.type == Builtin.Type.VOID &&
                m.type.func.args.length == 0)
            {
                std.stream.stdout.writeLine("invoke: " ~ m.name);
                (cast(void (*)(Test))m.address)(test);
            }
        }
    }
    else {
        std.stream.stdout.writeLine("cannot get test class");
    }
}

The above program iterates methods of "Test" class, and invoke the
each method when the name of the method starts with "test" and the
method returns void and requires no arguments. When you run the
program, you'll obtain the following message in stdout:

found: ignore
found: test_func1
invoke: test_func1
func1
found: test_func2
invoke: test_func2
func2
found: test_func3
invoke: test_func3
func3
found: test_ignore1
found: test_ignore2

Please comment if you are interested in this library.

------------------
 shinichiro.h
  s31552 mail.ecc.u-tokyo.ac.jp
  http://user.ecc.u-tokyo.ac.jp/~s31552/wp/
Aug 03 2004
next sibling parent reply parabolis <parabolis softhome.net> writes:
s31552 mail.ecc.u-tokyo.ac.jp wrote:

 I implemented a reflection library in D experimentally. Because now
 DMD compiler does not support reflection, my implementation is not
 smart.
 Please comment if you are interested in this library.
 
Well done! I was just discussing the possibility of reflection and I believe the thing you want to see is for ClassInfo to tell you what kinds of fields the instantiated object contains and in what order they appear. Is there anything else that you would need for full reflection?
Aug 03 2004
next sibling parent "Garett Bass" <gtbass studiotekne.com> writes:
I must admit, I haven't entirely grokked your reflection implementation.  I
just want to add that, for serialization purposes, it would also be very
handy if there were some means of reflecting upon a class's member
variables.  This would make it easy to create templates that could
serialize/deserialize an object to/from a stream.

Bravo,
Garett
Aug 03 2004
prev sibling parent "shinichiro.h" <s31552 mail.ecc.u-tokyo.ac.jp> writes:
 Well done! I was just discussing the possibility of reflection 
 and I believe the thing you want to see is for ClassInfo to tell 
 you what kinds of fields the instantiated object contains and in 
 what order they appear.
 
 Is there anything else that you would need for full reflection?
Yes, I think field infomation is needed. Object serialization is one of the big motivation for reflection. And if I continue to consider the demangle-base reflection, the name mangling rule of D language is not good now. We cannot distinguish C_f.C and C!(float): class C_f { class C {} } class C(T) {} C!(float) c; // They have the same "_Class_4test3C_f1C" symbol. // So this code causes link error. And I think implementing a user-friendly interface of constructor is difficult. We can construct objects manually with _d_newclass function. The code which call constructor will be like following: class Test { this(int i) {} } Class c = Class.forName(`test.Test`); void* ctor = c.getCtor(); ClassInfo ci = c.getClassInfo(); Object otmp = _d_newclass(ci); Object o = (cast(Object(*)(ClassInfo, int))ctor)(otmp, 1); It is complicated. ------------------ shinichiro.h
Aug 03 2004
prev sibling parent "Mickey Finn" <horizon blackhole.net> writes:
Nice!

<s31552 mail.ecc.u-tokyo.ac.jp> wrote in message
news:20040804140404.05de4e3a.s31552 mail.ecc.u-tokyo.ac.jp...
 I implemented a reflection library in D experimentally. Because now
 DMD compiler does not support reflection, my implementation is not
 smart.

 If you want to use my reflection library, you should prepare a file
 which contains symbol table using /MAP linker option. (or nm(1)
 command on Unix). The library read the symbol table from the file and
 demangle symbols. Since the symbols of D language has type
 infomations, the symbol table is enough to implement reflection.

 You can download the library here:
 http://user.ecc.u-tokyo.ac.jp/~s31552/wp/d/reflection.tar.bz2

 The file contains four files, reflection.d is the main library code,
 test_reflection.d is a test code, and build_*.sh are build
 scripts. The library supports both DMD and GDC. I check this library
 with DMD&Windows, DMD&Linux, GDC&Linux, GDC&MacOSX. Please note that
 the library has a lot of todos to simulate real reflection and the
 library will be no use if DMD supports reflection.

 A sample code of my library is the following:

 import reflection;

 class Test {
     void test_func1() { std.stream.stdout.writeLine("func1"); }
     void test_func2() { std.stream.stdout.writeLine("func2"); }
     void test_func3() { std.stream.stdout.writeLine("func3"); }
     int test_ignore1() { std.stream.stdout.writeLine("error"); return 0; }
     void test_ignore2(int i) { std.stream.stdout.writeLine("error"); }
     void ignore() { std.stream.stdout.writeLine("error"); }
 }

 int main(char[][] args) {
     Reflection.init(args[1]);

     Test test = new Test();
     Class c = Class.forName("test_reflection.Test");
     if (c !== null) {
         foreach (Method m; c.methods) {
             std.stream.stdout.writeLine("found: " ~ m.name);
             if (m.name.length >= 4 && m.name[0..4] == "test" &&
                 m.type.func.ret.builtin.type == Builtin.Type.VOID &&
                 m.type.func.args.length == 0)
             {
                 std.stream.stdout.writeLine("invoke: " ~ m.name);
                 (cast(void (*)(Test))m.address)(test);
             }
         }
     }
     else {
         std.stream.stdout.writeLine("cannot get test class");
     }
 }

 The above program iterates methods of "Test" class, and invoke the
 each method when the name of the method starts with "test" and the
 method returns void and requires no arguments. When you run the
 program, you'll obtain the following message in stdout:

 found: ignore
 found: test_func1
 invoke: test_func1
 func1
 found: test_func2
 invoke: test_func2
 func2
 found: test_func3
 invoke: test_func3
 func3
 found: test_ignore1
 found: test_ignore2

 Please comment if you are interested in this library.

 ------------------
  shinichiro.h
   s31552 mail.ecc.u-tokyo.ac.jp
   http://user.ecc.u-tokyo.ac.jp/~s31552/wp/
Aug 04 2004