www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Get specific functions of unknown type at runtime?

reply "F i L" <witte2008 gmail.com> writes:
My goal is this, to have an XML file:

     <!-- scene.xml -->
     <scene>
         <object class="Person" event="greet"/>
     </scene>

and a D file:

     module person;

     import std.stdio;

     class Person
     {
         void greet() {
             writeln("hello");
         }
     }

and then another D file:

     module main;

     import person;
     import std.xml;
     import std.file;

     static class Engine
     {
         static void delegate() event;
         static void callEvent() { event(); }
     }

     void main() {
         auto doc = new Document(read("scene.xml"));
         auto className = /* find class name in xml file */;
         auto eventName = /* find event name in xml file */;
         auto obj = Object.factory(className);

         Engine.event = /* get 'eventName' void in 'obj' */;

         for (/* some loop */) { Engine.callEvent(); }
     }

So yeah, basically is is possible to create a general object, 
then look at it's members at runtime? Through maybe a .classinfo 
or something? Or is this level of runtime reflection simply not 
supported in D (yet)? If so, what are my best alternative options 
here?
Dec 16 2012
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
The way I'd do it is to make an interface with a generic call 
method. The classes themselves fill this out using __traits.


interface SceneObject {
        void _callFunction(string name);
}

mixin template SceneObjectReflection() {
      override void _callFunction(string name) {
            foreach(funcname; __traits(derivedMembers, 
typeof(this))) {
                 static if(funcname[0] != '_') // just to skip 
stuff like _ctor
                 if(funcname == name) {
                     __traits(getMember, this, funcname)();
                     return;
                 }
            }
            throw new Exception("no such method");
      }
}

class Person : SceneObject {
     mixin SceneObjectReflection!();
     void greet() { writeln("hello"); }
}




Then you can use it like:

void main() {
    auto obj = cast(SceneObject) Object.factory("test6.Person") ;
    if(obj is null) throw new Exception("no such class");
    obj._callFunction("greet");
}



Where of course the class name and the function name are runtime 
strings.


It will still be a bumpy ride to make this work in a real world 
situation, but this is how I would get started.
Dec 16 2012
parent reply "F i L" <witte2008 gmail.com> writes:
 Adam D. Ruppe

Damn, I was afraid you where going to say to do something like 
that. It doesn't really work for what I'm thinking about, but 
thanks for confirming that my original code can't work.

I have an alternative in mind, but first, is there a possible way 
for a Super class to ask about a derivative's members during 
constructions? (I'm guessing not). Something like:

     import std.stdio, std.traits;

     class A
     {
         this() {
             alias typeof(this) type;
             static if (hasMember!(type, "foo")) {
                 auto top = cast(type) this;
                 top.foo();
             }
         }
     }

     class B : A
     {
         void foo() { writeln("foobar"); }
     }

     void main() {
         auto b = new B(); // prints: 'foobar'
     }

I assume there's no way (I can't get it to work), but I've heard 
odd things about 'typeof(this)' before, I just can't remember 
exactly what, so I figure it's worth asking about.

If not, I have an alternative way to accomplish what I want. It's 
just not as ideal. I really wish D has partial classes, that 
would be awesome.




 Jacob Carlborg

Thanks for the link.
Dec 16 2012
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-12-17 08:54, F i L wrote:
  Adam D. Ruppe

 Damn, I was afraid you where going to say to do something like that. It
 doesn't really work for what I'm thinking about, but thanks for
 confirming that my original code can't work.

 I have an alternative in mind, but first, is there a possible way for a
 Super class to ask about a derivative's members during constructions?
 (I'm guessing not). Something like:

      import std.stdio, std.traits;

      class A
      {
          this() {
              alias typeof(this) type;
              static if (hasMember!(type, "foo")) {
                  auto top = cast(type) this;
                  top.foo();
              }
          }
      }

      class B : A
      {
          void foo() { writeln("foobar"); }
      }

      void main() {
          auto b = new B(); // prints: 'foobar'
      }

 I assume there's no way (I can't get it to work), but I've heard odd
 things about 'typeof(this)' before, I just can't remember exactly what,
 so I figure it's worth asking about.

 If not, I have an alternative way to accomplish what I want. It's just
 not as ideal. I really wish D has partial classes, that would be awesome.
Don't know if this is what you need, but you could talk a look at: http://flectioned.kuehne.cn/ It's basically runtime reflection implemented by inspecting the symbol table in the currently running executable. Note that this is old D1 code. -- /Jacob Carlborg
Dec 17 2012
prev sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 17 December 2012 at 07:54:08 UTC, F i L wrote:
 I have an alternative in mind, but first, is there a possible 
 way for a Super class to ask about a derivative's members 
 during constructions? (I'm guessing not). Something like:
Not that I know of, no. Though maybe a templated constructor could so some magic. class SceneObject { this(T)(T t) { ... } } class Person : SceneObject { this() { super(this); } // calls the templated superclass magic, which will have T == Person } But this isn't that much different than the mixin approach in that you still have to do something special with the child classes. My dmd segfaults when I don't put a constructor in the child class at all... I think there's bug fixes coming in the new dmd about these templated constructors so it might get better. idk.
Dec 17 2012
parent "F i L" <witte2008 gmail.com> writes:
Okay, thanks for the help folks.
Dec 17 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-12-17 02:39, F i L wrote:
 My goal is this, to have an XML file:

      <!-- scene.xml -->
      <scene>
          <object class="Person" event="greet"/>
      </scene>

 and a D file:

      module person;

      import std.stdio;

      class Person
      {
          void greet() {
              writeln("hello");
          }
      }

 and then another D file:

      module main;

      import person;
      import std.xml;
      import std.file;

      static class Engine
      {
          static void delegate() event;
          static void callEvent() { event(); }
      }

      void main() {
          auto doc = new Document(read("scene.xml"));
          auto className = /* find class name in xml file */;
          auto eventName = /* find event name in xml file */;
          auto obj = Object.factory(className);

          Engine.event = /* get 'eventName' void in 'obj' */;

          for (/* some loop */) { Engine.callEvent(); }
      }

 So yeah, basically is is possible to create a general object, then look
 at it's members at runtime? Through maybe a .classinfo or something? Or
 is this level of runtime reflection simply not supported in D (yet)? If
 so, what are my best alternative options here?
For the serialization part you could have a look at Orange: https://github.com/jacob-carlborg/orange It won't handle the dynamic methods though. -- /Jacob Carlborg
Dec 16 2012