www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Introspection/Reflection/etc on Linux

reply J Arrizza <cppgent0 gmail.com> writes:
I'm trying to write some sample code to:
  1 create an object via it's name
  2 search an object for it's functions
  3 call a static function in a class
  4 call a non-static function in an object

#1, #2 and #3 were straightforward. But  #4 looks like it's not possible in
DMD 2.0.

I found this:

http://www.digitalmars.com/d/archives/digitalmars/D/announce/Runtime_reflection_9949.html

which implies #4 is doable in Windows but not Linux. I'm using Linux 64-bit
Ubuntu.

Any other avenues I can chase?

TIA,
John
Oct 18 2011
next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 18 Oct 2011 12:48:47 -0400, J Arrizza <cppgent0 gmail.com> wrote:

 I'm trying to write some sample code to:
   1 create an object via it's name
   2 search an object for it's functions
   3 call a static function in a class
   4 call a non-static function in an object

 #1, #2 and #3 were straightforward. But  #4 looks like it's not possible in
 DMD 2.0.

 I found this:

 http://www.digitalmars.com/d/archives/digitalmars/D/announce/Runtime_reflection_9949.html

 which implies #4 is doable in Windows but not Linux. I'm using Linux 64-bit
 Ubuntu.

 Any other avenues I can chase?

 TIA,
 John
You could try out my improved variant implementation: https://jshare.johnshopkins.edu/rjacque2/public_html/variant.mht https://jshare.johnshopkins.edu/rjacque2/public_html/variant.d Example: import variant; class Foo { int x; } void main(string[] args) { Variant.__register!Foo; Variant var = Object.factory( typeid(Foo).toString ); var.__reflect("x",Variant(10)); // or explicitly assert(var.__reflect("x") == 10); return; }
Oct 18 2011
parent reply J Arrizza <cppgent0 gmail.com> writes:
Robert,

I tried using variant.d using your exact test program below and I got
compiler errors:

$ dmd  variant.d dtest.d
variant.d(273): Error: no property 'length' for type 'Result'
variant.d(273): Error: no property 'length' for type 'Result'
variant.d(274): Error: no property 'length' for type 'Result'
variant.d(274): Error: no property 'length' for type 'Result'
variant.d(274): Error: no property 'length' for type 'Result'
variant.d(275): Error: no property 'length' for type 'Result'
variant.d(277): Error: no property 'length' for type 'Result'
variant.d(277): Error: no property 'length' for type 'Result'
variant.d(277): Error: no property 'length' for type 'Result'
variant.d(277): Error: no property 'length' for type 'Result'
variant.d(280): Error: no property 'length' for type 'Result'
$ dmd -v
DMD64 D Compiler v2.055

Am I missing a switch or something?

John

On Tue, Oct 18, 2011 at 8:13 PM, Robert Jacques <sandford jhu.edu> wrote:

 You could try out my improved variant implementation:

 https://jshare.johnshopkins.**edu/rjacque2/public_html/**variant.mht<https://jshare.johnshopkins.edu/rjacque2/public_html/variant.mht>

 https://jshare.johnshopkins.**edu/rjacque2/public_html/**variant.d<https://jshare.johnshopkins.edu/rjacque2/public_html/variant.d>

 Example:

 import variant;

 class Foo { int x; }
 void main(string[] args) {
    Variant.__register!Foo;
    Variant var = Object.factory( typeid(Foo).toString );
    var.__reflect("x",Variant(10))**; // or explicitly
    assert(var.__reflect("x") == 10);
    return;
 }
-- John blog: http://arrizza.blogspot.com/ web: http://www.arrizza.com/
Nov 01 2011
next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 01 Nov 2011 14:42:42 -0400, J Arrizza <cppgent0 gmail.com> wrote:

 Robert,

 I tried using variant.d using your exact test program below and I got
 compiler errors:

 $ dmd  variant.d dtest.d
 variant.d(273): Error: no property 'length' for type 'Result'
 variant.d(273): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(275): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(280): Error: no property 'length' for type 'Result'
 $ dmd -v
 DMD64 D Compiler v2.055

 Am I missing a switch or something?

 John
(I apologize if this gets sent twice, my newsreader is acting up) Nope, (hopefully) just patches. I maintain a list of the bugzilla patches (i.e. http://d.puremagic.com/issues/show_bug.cgi?id=5155) I've applied at the top of the file. But, mostly those are so DMD doesn't ICE; I've never seen this particular error before and am not sure how to interpret it. Hmm.. I don't use a Result type, but std.algoroithm does and one of the patches I always use is 6256 (http://d.puremagic.com/issues/show_bug.cgi?id=6256), which addresses length for Map.
Nov 02 2011
next sibling parent J Arrizza <cppgent0 gmail.com> writes:
Robert,

This stub shows the issue:

import std.stdio;
import std.range;

void main(string[] args)
  {
    string id = "somestring";
    auto rid = retro(id);
    writeln(rid.length);
  }

$: dmd  dtest.d
dtest.d(8): Error: no property 'length' for type 'Result'


I haven't applied either patch you mentioned below. Neither patch seems to
address retro() or Result...

John



On Wed, Nov 2, 2011 at 6:43 AM, Robert Jacques <sandford jhu.edu> wrote:

 On Tue, 01 Nov 2011 14:42:42 -0400, J Arrizza <cppgent0 gmail.com> wrote:

  Robert,
 I tried using variant.d using your exact test program below and I got
 compiler errors:

 $ dmd  variant.d dtest.d
 variant.d(273): Error: no property 'length' for type 'Result'
 variant.d(273): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(275): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(280): Error: no property 'length' for type 'Result'
 $ dmd -v
 DMD64 D Compiler v2.055

 Am I missing a switch or something?

 John
(I apologize if this gets sent twice, my newsreader is acting up) Nope, (hopefully) just patches. I maintain a list of the bugzilla patches (i.e. http://d.puremagic.com/issues/**show_bug.cgi?id=5155<http://d.puremagic.com/issues/show_bug.cgi?id=5155>) I've applied at the top of the file. But, mostly those are so DMD doesn't ICE; I've never seen this particular error before and am not sure how to interpret it. Hmm.. I don't use a Result type, but std.algoroithm does and one of the patches I always use is 6256 (http://d.puremagic.com/** issues/show_bug.cgi?id=6256<http://d.puremagic.com/issues/show_bug.cgi?id=6256>), which addresses length for Map.
-- John blog: http://arrizza.blogspot.com/ web: http://www.arrizza.com/
Nov 03 2011
prev sibling parent reply J Arrizza <cppgent0 gmail.com> writes:
PS, this version works and prints "10" for the length:

    string id = "somestring";
    auto rid = retro(id);
    //writeln(rid.length);
    writeln(rid.source.length);


On Thu, Nov 3, 2011 at 3:26 AM, J Arrizza <cppgent0 gmail.com> wrote:

 Robert,

 This stub shows the issue:

 import std.stdio;
 import std.range;

 void main(string[] args)
   {
     string id = "somestring";
     auto rid = retro(id);
     writeln(rid.length);
   }

 $: dmd  dtest.d
 dtest.d(8): Error: no property 'length' for type 'Result'


 I haven't applied either patch you mentioned below. Neither patch seems to
 address retro() or Result...

 John
Nov 03 2011
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 03 Nov 2011 06:28:30 -0400, J Arrizza <cppgent0 gmail.com> wrote:
 PS, this version works and prints "10" for the length:

     string id = "somestring";
     auto rid = retro(id);
     //writeln(rid.length);
     writeln(rid.source.length);


 On Thu, Nov 3, 2011 at 3:26 AM, J Arrizza <cppgent0 gmail.com> wrote:

 Robert,

 This stub shows the issue:

 import std.stdio;
 import std.range;

 void main(string[] args)
   {
     string id = "somestring";
     auto rid = retro(id);
     writeln(rid.length);
   }

 $: dmd  dtest.d
 dtest.d(8): Error: no property 'length' for type 'Result'


 I haven't applied either patch you mentioned below. Neither patch seems to
 address retro() or Result...

 John
Thanks John for tracking this down and finding a work around. It seems that the behavior of retro changed between 2.053 and 2.055. As you've probably already found, the errors are in the typeinfo2stringof function on line 245 of the currently uploaded variant.
Nov 03 2011
next sibling parent J Arrizza <cppgent0 gmail.com> writes:
Here's my changes to it:

   //Convert a string representation of a type, produced by typeinfo into a
.stringof representation
    string typeinfo2stringof(string id){
        auto rid = retro(id);
        auto r1  = find(rid, '.');
        auto rb  = find(rid, '!');
        auto r1len = r1.source.length;

        if(!rb.empty) {
            auto r1a = r1;
                 r1a.popFront;
                  rb.popFront;
            auto r2  = find(r1a,'.');
            auto r1alen = r1a.source.length;
            auto r2len = r2.source.length;
            auto rblen = rb.source.length;
            assert(id[r2len..rblen]==id[r1len..r1len+ (rblen-r2len)],
"Internal error in std.Variant regarding converting toString to stringof.");
            if(r1len+(rblen-r2len) >= id.length ) {
                id = id[r2len..r1alen];
            } else {
                id = id[r2len..r1alen]~id[r1len +(rblen-r2len)..$];
            }
        } else {
            id = id[r1len..$];
        }
        return id;
    }
Nov 03 2011
prev sibling parent J Arrizza <cppgent0 gmail.com> writes:
And here's a working example:

import std.stdio;
import variant;
import std.string;
import std.conv;

//----
class Base
  {
    private int y;  //check if a variable causes any problems

    //run all member functions that start with "in"
    public void RunAllIn(alias T) ()
    {
      writeln("RunAllIn: ", typeid(T));
      Variant.__register!T;
      Variant var = this;
      foreach (i, m; __traits(derivedMembers, T))
        {
        if (!startsWith(m, "in"))
          {
            continue;
          }

        writeln("== i=", i, "  m=", m);
        var.__reflect(m);
        }
    }
  }

//----
class Bob : Base
  {
    private int x;  //check if a variable causes any problems
    //private int inx;  //causes an exception

    this()
      {
        RunAllIn!Bob;
      }

    public void inBob1()
      {
        writeln("   in bob : inBob1()");
      }

    public void inBob2()
      {
        writeln("   in bob : inBob2()");
      }
  }

//----
class Jane: Base
  {
    this()
      {
        RunAllIn!Jane;
      }

    public void inJane1()
      {
        writeln("   in jane : inJane1()");
      }

    public void inJane2()
      {
        writeln("   in jane : inJane2()");
      }
  }

void main(string[] args)
  {
    new Bob();
    new Jane();
  }


The output is:

$ rm -f dtest; dmd   dtest.d variant.d  -ofdtest; ./dtest
RunAllIn: dtest.Bob
== i=2  m=inBob1
   in bob : inBob1()
== i=3  m=inBob2
   in bob : inBob2()
RunAllIn: dtest.Jane
== i=1  m=inJane1
   in jane : inJane1()
== i=2  m=inJane2
   in jane : inJane2()


Perfect, thanks Robert! Works like a charm.
Nov 03 2011
prev sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 01 Nov 2011 14:42:42 -0400, J Arrizza <cppgent0 gmail.com> wrote:
 Robert,

 I tried using variant.d using your exact test program below and I got
 compiler errors:

 $ dmd  variant.d dtest.d
 variant.d(273): Error: no property 'length' for type 'Result'
 variant.d(273): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(274): Error: no property 'length' for type 'Result'
 variant.d(275): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(277): Error: no property 'length' for type 'Result'
 variant.d(280): Error: no property 'length' for type 'Result'
 $ dmd -v
 DMD64 D Compiler v2.055

 Am I missing a switch or something?

 John
Nope, (hopefully) just patches. I maintain a list of the bugzilla patches (i.e. http://d.puremagic.com/issues/show_bug.cgi?id=5155) I've applied at the top of the file. But, mostly those are so DMD doesn't ICE; I've never seen this particular error before and am not sure how to interpret it. Hmm.. I don't use a Result type, but std.algoroithm does and one of the patches I always use is 6256 (http://d.puremagic.com/issues/show_bug.cgi?id=6256), which addresses length for Map.
Nov 07 2011
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-10-18 18:48, J Arrizza wrote:
 I'm trying to write some sample code to:
    1 create an object via it's name
    2 search an object for it's functions
    3 call a static function in a class
    4 call a non-static function in an object

 #1, #2 and #3 were straightforward. But  #4 looks like it's not possible
 in DMD 2.0.

 I found this:

 http://www.digitalmars.com/d/archives/digitalmars/D/announce/Runtime_reflection_9949.html

 which implies #4 is doable in Windows but not Linux. I'm using Linux
 64-bit Ubuntu.

 Any other avenues I can chase?

 TIA,
 John
How about doing something like this: class Foo { void bar () { writeln("bar"); } } void main () { auto foo = new Foo; auto members = __traits(derivedMembers, Foo); void delegate () dg; foreach (i, m ; members) if (m == "bar") dg.funcptr = cast(void function()) foo.classinfo.vtbl[i + 6]; dg.ptr = cast(void*) foo; dg(); } -- /Jacob Carlborg
Oct 19 2011
parent reply J Arrizza <cppgent0 gmail.com> writes:
Just noticed an odd thing when I was trying Jacob's code.

This works great:
    auto x = new someClass();
    Object o = x;
    void delegate() dg;
    foreach(i, m; __traits(derivedMembers, someClass))
      {
        writeln("i=", i, "  m=", m);

        if(m != "__ctor")
          {
            dg.funcptr = cast(void function()) o.classinfo.vtbl[i + 6];
            dg.ptr = cast(void*) o;
            dg();
          }
      }

but this doesn't (it segfaults):
    Object o = Object.factory("someClass");
    void delegate() dg;
    foreach(i, m; __traits(derivedMembers, someClass))
      {
        writeln("i=", i, "  m=", m);

        if(m != "__ctor")
          {
            dg.funcptr = cast(void function()) o.classinfo.vtbl[i + 6];
            dg.ptr = cast(void*) o;
            dg();
          }
      }


Is the object returned by Object.factory() not the same somehow as the one
returned by new()?

John
Oct 19 2011
parent reply Jacob Carlborg <doob me.com> writes:
On 2011-10-19 11:24, J Arrizza wrote:
 Just noticed an odd thing when I was trying Jacob's code.

 This works great:
      auto x = new someClass();
      Object o = x;
      void delegate() dg;
      foreach(i, m; __traits(derivedMembers, someClass))
        {
          writeln("i=", i, "  m=", m);

          if(m != "__ctor")
            {
              dg.funcptr = cast(void function()) o.classinfo.vtbl[i + 6];
              dg.ptr = cast(void*) o;
              dg();
            }
        }

 but this doesn't (it segfaults):
      Object o = Object.factory("someClass");
      void delegate() dg;
      foreach(i, m; __traits(derivedMembers, someClass))
        {
          writeln("i=", i, "  m=", m);

          if(m != "__ctor")
            {
              dg.funcptr = cast(void function()) o.classinfo.vtbl[i + 6];
              dg.ptr = cast(void*) o;
              dg();
            }
        }


 Is the object returned by Object.factory() not the same somehow as the
 one returned by new()?

 John
For Object.factory you need the fully qualified name, i.e. SomeClass.classinfo.name. If Object.factory can't find a class name it will just return null. -- /Jacob Carlborg
Oct 19 2011
parent reply J Arrizza <cppgent0 gmail.com> writes:
Yup, didn't check for null, damn it. Can I blame it on working on it at
2:30AM? Forget the excuse, I just didn't check for null.

For future reference, the fully qualified name for SomeClass is
"SomeClass.SomeClass".   If I create class Bob in the SomeClass file
"SomeClass.Bob". The first node is the file name, the second the actual name
of the class. I imagine there is additional complications for nested
classes.

Thanks Jacob,
John


For Object.factory you need the fully qualified name, i.e.
 SomeClass.classinfo.name. If Object.factory can't find a class name it
 will just return null.

 --
 /Jacob Carlborg
Oct 19 2011
parent Jacob Carlborg <doob me.com> writes:
On 2011-10-20 07:44, J Arrizza wrote:
 Yup, didn't check for null, damn it. Can I blame it on working on it at
 2:30AM? Forget the excuse, I just didn't check for null.

 For future reference, the fully qualified name for SomeClass is
 "SomeClass.SomeClass".   If I create class Bob in the SomeClass file
 "SomeClass.Bob". The first node is the file name, the second the actual
 name of the class. I imagine there is additional complications for
 nested classes.
The fully qualified class name includes the module the class is defined in, if you're unsure you can get it by running: writeln(SomeClass.classinfo.name);
 Thanks Jacob,
 John


     For Object.factory you need the fully qualified name, i.e.
     SomeClass.classinfo.name <http://SomeClass.classinfo.name>. If
     Object.factory can't find a class name it will just return null.

     --
     /Jacob Carlborg
-- /Jacob Carlborg
Oct 19 2011
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2011-10-18 18:48, J Arrizza wrote:
 I'm trying to write some sample code to:
    1 create an object via it's name
    2 search an object for it's functions
    3 call a static function in a class
    4 call a non-static function in an object

 #1, #2 and #3 were straightforward. But  #4 looks like it's not possible
 in DMD 2.0.

 I found this:

 http://www.digitalmars.com/d/archives/digitalmars/D/announce/Runtime_reflection_9949.html

 which implies #4 is doable in Windows but not Linux. I'm using Linux
 64-bit Ubuntu.

 Any other avenues I can chase?

 TIA,
 John
Runtime reflection by inspecting the symbol table of the currently executing application: http://flectioned.kuehne.cn/ -- /Jacob Carlborg
Oct 19 2011
parent J Arrizza <cppgent0 gmail.com> writes:
Jacob, by the way, I did try flectioned and unfortunately it failed to
compile.

   http://flectioned.kuehne.cn/

According to the comments it should work in windows or linux and it should
work with D1 and D2. However I got quite a few compiler errors using:

    $ dmd -v
    DMD64 D Compiler v2.055

I tried fixing as many as I could, but at this point in my D skills, it was
beyond me.

It looked promising though. I did something similar by parsing the PE format
of Windows DLLs http://www.arrizza.com/unittesters/utx/utx.html . Kind of
kludgy though. I had to de-mangle the names in the internal PE dictionary,
making it wholly reliant on the microsoft compiler. But it worked...

John


On Wed, Oct 19, 2011 at 1:22 AM, Jacob Carlborg <doob me.com> wrote:

 Runtime reflection by inspecting the symbol table of the currently
 executing application: http://flectioned.kuehne.cn/

 --
 /Jacob Carlborg
-- John blog: http://arrizza.blogspot.com/ web: http://www.arrizza.com/
Oct 23 2011