digitalmars.D.learn - How to dynamically call class virtual method dynamically
- Frustrated (37/37) Apr 01 2014 Basically in programming to interfaces I need to decide to call a
- John Colvin (33/70) Apr 01 2014 The traditional OO approach would probably be this:
- John Colvin (11/14) Apr 01 2014 Sorry, I should clarify that:
- Steven Schveighoffer (11/45) Apr 01 2014 Detecting whether bar exists can only happen at compile time, since an
- Frustrated (36/93) Apr 01 2014 It seems logical to me that I should be able to achieve what I
- anonymous (19/28) Apr 01 2014 [...]
- Steven Schveighoffer (21/106) Apr 01 2014 There is no definition for B's vtable according to A. It just looks like...
- Frustrated (50/174) Apr 01 2014 Here is a basic outline of a possible approach. I do not believe
Basically in programming to interfaces I need to decide to call a virtual method of an object if it exists else call a final method in the interface: interface A { static final void foo() { ... } } class B : A { void bar() { ... } // optional } class C : B { void bar() { ... } // optional } void main() { A a = new B; // or new C; // if a.bar exists call it, else call foo // code should work independent of the classes. (there might be more) } The point of the code is simply to allow the class to implement bar optionally but provide default behavior with foo. I need a way to dynamically determine if bar exists and fall back on foo. This should be possible. e.g., suppose class B : A { } then I would like to b.bar() to actually call A.foo() (since bar doesn't exist in b). I guess the exist way would be to create an opDispatch and have it call foo if bar is passed. This works great and does everything I need it to except requires adding the code in the class which I can't have. Also I'm not sure how it would work with virtual methods. I've tried using hasMember but since my object is cast to a type of Object it never works.
Apr 01 2014
On Tuesday, 1 April 2014 at 07:31:43 UTC, Frustrated wrote:Basically in programming to interfaces I need to decide to call a virtual method of an object if it exists else call a final method in the interface: interface A { static final void foo() { ... } } class B : A { void bar() { ... } // optional } class C : B { void bar() { ... } // optional } void main() { A a = new B; // or new C; // if a.bar exists call it, else call foo // code should work independent of the classes. (there might be more) } The point of the code is simply to allow the class to implement bar optionally but provide default behavior with foo. I need a way to dynamically determine if bar exists and fall back on foo. This should be possible. e.g., suppose class B : A { } then I would like to b.bar() to actually call A.foo() (since bar doesn't exist in b). I guess the exist way would be to create an opDispatch and have it call foo if bar is passed. This works great and does everything I need it to except requires adding the code in the class which I can't have. Also I'm not sure how it would work with virtual methods. I've tried using hasMember but since my object is cast to a type of Object it never works.The traditional OO approach would probably be this: import std.stdio; class A { static final void foo() { writeln("A.foo"); } void bar() { foo(); } } class B : A { override void bar() { writeln("B.bar"); } // optional } class C : A {} void main() { A a0 = new B; // or new C; A a1 = new C; // or new C; a0.bar(); //B.bar a1.bar(); //A.foo } Also, bear in mind that polymorphism is one-way: you can call base class methods through an inherited class reference, but not the other way around. interface A {} class B : A { void bar() {} } void main() { A a = new B; a.bar(); // Error: no property 'bar' for type 'A' }
Apr 01 2014
On Tuesday, 1 April 2014 at 09:12:41 UTC, John Colvin wrote:Also, bear in mind that polymorphism is one-way: you can call base class methods through an inherited class reference, but not the other way around.Sorry, I should clarify that: Given an inheritance tree with the base class class at the bottom, calls can always be made down the tree (inheriting class reference calling method in inherited class), but you can only call up the tree via overriden virtual functions (inherited class reference calling inheriting class functions). A new method that isn't present in the base class is by definition not overriding anything in the base class. Therefore you cannot call it from a base class reference, that would mean moving up the inheritance tree.
Apr 01 2014
On Tue, 01 Apr 2014 03:31:41 -0400, Frustrated <Who where.com> wrote:Basically in programming to interfaces I need to decide to call a virtual method of an object if it exists else call a final method in the interface: interface A { static final void foo() { ... } } class B : A { void bar() { ... } // optional } class C : B { void bar() { ... } // optional } void main() { A a = new B; // or new C; // if a.bar exists call it, else call foo // code should work independent of the classes. (there might be more) } The point of the code is simply to allow the class to implement bar optionally but provide default behavior with foo. I need a way to dynamically determine if bar exists and fall back on foo. This should be possible. e.g., suppose class B : A { } then I would like to b.bar() to actually call A.foo() (since bar doesn't exist in b). I guess the exist way would be to create an opDispatch and have it call foo if bar is passed. This works great and does everything I need it to except requires adding the code in the class which I can't have. Also I'm not sure how it would work with virtual methods.Detecting whether bar exists can only happen at compile time, since an instance of A has no mechanism to detect whether it has bar. D does not have very good runtime introspection, that would have to be built into the TypeInfo struct (the mechanism exists to do it, but it has never been used for that). You could use this templates, but that would only work if the type of the derived class is known at compile time. This problem could easily be solved by virtual methods with default implementation. -Steve
Apr 01 2014
On Tuesday, 1 April 2014 at 12:20:06 UTC, Steven Schveighoffer wrote:On Tue, 01 Apr 2014 03:31:41 -0400, Frustrated <Who where.com> wrote:It seems logical to me that I should be able to achieve what I what. Suppose I have an object cast to it's interface: A a = new B; when I call a.This() it will call the method in the interface. Either This is a virtual method or a final method. Suppose it is a Final method since if it is virtual there is no problem. Now suppose B implements That as a virtual method that doesn't exist in A. Since a IS a B, That exists in it's vtable. I should be able to call it: a.That(); // Calls B's That(). Of course this doesn't work directly because That() is not part of the interface. Regardless though, it still exists: (cast(B)a).That(); // Works But the only problem is that the cast(B) is required and is a trick to get the compiler to do what I want. But we know that a is of type B. e.g., typeof(cast(Object)a) returns B, right? Basically, it should be very easy for the compiler to internally cast a object to it's actual type(since that is contained in the object information, even if it's cast to something else) and call members on it. Of course, I'm not asking for an internal way. I could be mistaken but isn't `A a = new B` just a facade and a really is of type B? If so, isn't there a way to get the true type of a at runtime? If so, then can't we cast a to its true type at runtime and access its members properly? e.g., suppose truecast(a) returns a as the actual object that a was created as(in this case B, not A). Then truecast(a).That() would work. I'm sort of looking for the truecast function/template. Of course, if D doesn't store information about the actual type an object is inside it(which it doesn't AFAIK) then you can't truecast.Basically in programming to interfaces I need to decide to call a virtual method of an object if it exists else call a final method in the interface: interface A { static final void foo() { ... } } class B : A { void bar() { ... } // optional } class C : B { void bar() { ... } // optional } void main() { A a = new B; // or new C; // if a.bar exists call it, else call foo // code should work independent of the classes. (there might be more) } The point of the code is simply to allow the class to implement bar optionally but provide default behavior with foo. I need a way to dynamically determine if bar exists and fall back on foo. This should be possible. e.g., suppose class B : A { } then I would like to b.bar() to actually call A.foo() (since bar doesn't exist in b). I guess the exist way would be to create an opDispatch and have it call foo if bar is passed. This works great and does everything I need it to except requires adding the code in the class which I can't have. Also I'm not sure how it would work with virtual methods.Detecting whether bar exists can only happen at compile time, since an instance of A has no mechanism to detect whether it has bar. D does not have very good runtime introspection, that would have to be built into the TypeInfo struct (the mechanism exists to do it, but it has never been used for that). You could use this templates, but that would only work if the type of the derived class is known at compile time. This problem could easily be solved by virtual methods with default implementation. -Steve
Apr 01 2014
On Tuesday, 1 April 2014 at 19:00:18 UTC, Frustrated wrote:A a = new B;[...] Now suppose B implements That as a virtual method that doesn't exist in A. [...]e.g., typeof(cast(Object)a) returns B, right?No, it's Object. You're looking for typeid which returns a TypeInfo [1] which is runtime information about the type. For classes that's for the most derived one (here: B).I could be mistaken but isn't `A a = new B` just a facade and a really is of type B? If so, isn't there a way to get the true type of a at runtime? If so, then can't we cast a to its true type at runtime and access its members properly?Yes, all true. But you need the target type at compile time to cast.e.g., suppose truecast(a) returns a as the actual object that a was created as(in this case B, not A). Then truecast(a).That() would work.When different implementations of A have different Thats, they are not related in any way. And the compiler doesn't know about (possibly future) implementations when working on code that uses just the interface A. So, as far as I can see, truecast(a).That() would have to be a string lookup at runtime. And then the members' types would be dynamic, too, of course. I have no idea how one would go about that. My best guess is that all of D's type system would have to be duplicated at runtime. [1] http://dlang.org/phobos/object.html#TypeInfo
Apr 01 2014
On Tue, 01 Apr 2014 15:00:17 -0400, Frustrated <Who where.com> wrote:On Tuesday, 1 April 2014 at 12:20:06 UTC, Steven Schveighoffer wrote:There is no definition for B's vtable according to A. It just looks like an array of void pointers. In other words, there's no possible way, without knowing B's type structure, to know which entry in the vtable is 'That'.On Tue, 01 Apr 2014 03:31:41 -0400, Frustrated <Who where.com> wrote:It seems logical to me that I should be able to achieve what I what. Suppose I have an object cast to it's interface: A a = new B; when I call a.This() it will call the method in the interface. Either This is a virtual method or a final method. Suppose it is a Final method since if it is virtual there is no problem. Now suppose B implements That as a virtual method that doesn't exist in A. Since a IS a B, That exists in it's vtable. I should be able to call it: a.That(); // Calls B's That().Basically in programming to interfaces I need to decide to call a virtual method of an object if it exists else call a final method in the interface: interface A { static final void foo() { ... } } class B : A { void bar() { ... } // optional } class C : B { void bar() { ... } // optional } void main() { A a = new B; // or new C; // if a.bar exists call it, else call foo // code should work independent of the classes. (there might be more) } The point of the code is simply to allow the class to implement bar optionally but provide default behavior with foo. I need a way to dynamically determine if bar exists and fall back on foo. This should be possible. e.g., suppose class B : A { } then I would like to b.bar() to actually call A.foo() (since bar doesn't exist in b). I guess the exist way would be to create an opDispatch and have it call foo if bar is passed. This works great and does everything I need it to except requires adding the code in the class which I can't have. Also I'm not sure how it would work with virtual methods.Detecting whether bar exists can only happen at compile time, since an instance of A has no mechanism to detect whether it has bar. D does not have very good runtime introspection, that would have to be built into the TypeInfo struct (the mechanism exists to do it, but it has never been used for that). You could use this templates, but that would only work if the type of the derived class is known at compile time. This problem could easily be solved by virtual methods with default implementation. -SteveOf course this doesn't work directly because That() is not part of the interface. Regardless though, it still exists: (cast(B)a).That(); // WorksBecause you have (at runtime) determined that a actually IS a 'B'.But the only problem is that the cast(B) is required and is a trick to get the compiler to do what I want.It's not a "trick", it's a runtime check. It basically is saying "if a is actually a B, then call B.That, otherwise segfault"But we know that a is of type B.The compiler/runtime does not know that.e.g., typeof(cast(Object)a) returns B, right?You are thinking of typeid. But the runtime information does not contain any way to figure out which location 'That' is at. What you are really looking for is runtime introspection, similar to Java compile-time introspection.I could be mistaken but isn't `A a = new B` just a facade and a really is of type B?a is of type A, and it points at an instance of B.If so, isn't there a way to get the true type of a at runtime? If so, then can't we cast a to its true type at runtime and access its members properly?You can get at B's typeinfo, but that doesn't contain a way to call arbitrarily named functions.e.g., suppose truecast(a) returns a as the actual object that a was created as(in this case B, not A). Then truecast(a).That() would work.With the correct implementation of RTInfo inside object.di, you could possibly make this work. It would be kind of cool. It would be a TON of work to make this a reality. -Steve
Apr 01 2014
On Tuesday, 1 April 2014 at 19:52:47 UTC, Steven Schveighoffer wrote:On Tue, 01 Apr 2014 15:00:17 -0400, Frustrated <Who where.com> wrote:Here is a basic outline of a possible approach. I do not believe it is the best way import std.stdio, std.cstream; interface A { public final void opDispatch(string m)() { opDispatchImpl(m); } protected bool opDispatchImpl(string m); // void bar() { writeln("hello"); } // possible but name conflict } class B : A { void bar() { writeln("asdfasdf"); } override bool opDispatchImpl(string m) { if (m == "bar") bar(); return false; } } void main() { A a = new B; B b = new B; a.bar(); // Wow, A doesn't have a bar yet we call it?!?! b.bar(); din.getc(); } Note that a does not have a bar() but yet it is called. opDispatch on the interface passes it down to the class. This is messy and not very robust(how to handle general functions(arbitrary parameters and return types easily). Note that bar could be final in all cases(no vtable necessary but slow). Essentially opDispatch would implement a vtable look up(the if's) but based on the names of the methods. If D's vtable's contained the signatures of the functions it would be somewhat easy to do all this without having to clutter up the types with dispatching(but it would be slower because one would have to search the right function). D would have to allow us to call a function in a dynamic way(no I imagine one could make such a vtable at compile time and do the searching. Look up the methods by classname then methodname should be easy enough(they would be string lookups).On Tuesday, 1 April 2014 at 12:20:06 UTC, Steven Schveighoffer wrote:There is no definition for B's vtable according to A. It just looks like an array of void pointers. In other words, there's no possible way, without knowing B's type structure, to know which entry in the vtable is 'That'.On Tue, 01 Apr 2014 03:31:41 -0400, Frustrated <Who where.com> wrote:It seems logical to me that I should be able to achieve what I what. Suppose I have an object cast to it's interface: A a = new B; when I call a.This() it will call the method in the interface. Either This is a virtual method or a final method. Suppose it is a Final method since if it is virtual there is no problem. Now suppose B implements That as a virtual method that doesn't exist in A. Since a IS a B, That exists in it's vtable. I should be able to call it: a.That(); // Calls B's That().Basically in programming to interfaces I need to decide to call a virtual method of an object if it exists else call a final method in the interface: interface A { static final void foo() { ... } } class B : A { void bar() { ... } // optional } class C : B { void bar() { ... } // optional } void main() { A a = new B; // or new C; // if a.bar exists call it, else call foo // code should work independent of the classes. (there might be more) } The point of the code is simply to allow the class to implement bar optionally but provide default behavior with foo. I need a way to dynamically determine if bar exists and fall back on foo. This should be possible. e.g., suppose class B : A { } then I would like to b.bar() to actually call A.foo() (since bar doesn't exist in b). I guess the exist way would be to create an opDispatch and have it call foo if bar is passed. This works great and does everything I need it to except requires adding the code in the class which I can't have. Also I'm not sure how it would work with virtual methods.Detecting whether bar exists can only happen at compile time, since an instance of A has no mechanism to detect whether it has bar. D does not have very good runtime introspection, that would have to be built into the TypeInfo struct (the mechanism exists to do it, but it has never been used for that). You could use this templates, but that would only work if the type of the derived class is known at compile time. This problem could easily be solved by virtual methods with default implementation. -SteveOf course this doesn't work directly because That() is not part of the interface. Regardless though, it still exists: (cast(B)a).That(); // WorksBecause you have (at runtime) determined that a actually IS a 'B'.But the only problem is that the cast(B) is required and is a trick to get the compiler to do what I want.It's not a "trick", it's a runtime check. It basically is saying "if a is actually a B, then call B.That, otherwise segfault"But we know that a is of type B.The compiler/runtime does not know that.e.g., typeof(cast(Object)a) returns B, right?You are thinking of typeid. But the runtime information does not contain any way to figure out which location 'That' is at. What you are really looking for is runtime introspection, been implemented. We only have compile-time introspection.I could be mistaken but isn't `A a = new B` just a facade and a really is of type B?a is of type A, and it points at an instance of B.If so, isn't there a way to get the true type of a at runtime? If so, then can't we cast a to its true type at runtime and access its members properly?You can get at B's typeinfo, but that doesn't contain a way to call arbitrarily named functions.e.g., suppose truecast(a) returns a as the actual object that a was created as(in this case B, not A). Then truecast(a).That() would work.With the correct implementation of RTInfo inside object.di, you could possibly make this work. It would be kind of cool. It would be a TON of work to make this a reality. -Steve
Apr 01 2014