__traits and determining all overridable functions

Christopher Wright dhasenan at gmail.com
Mon Nov 12 07:59:45 PST 2007


Steven Schveighoffer wrote:
> Hi,
> 
> I was thinking of making a template that derives from an object, but 
> intercepts all calls to virtual functions automatically.  This could be used 
> for something like RMI or .net Remoting to allow a call to either execute a 
> method locally or in an object on a server if connected.

http://dsource.org/projects/dmocks/browser/trunk/dmocks
Take a look at MockObject.d and MethodMock.d -- they have pretty much 
everything you need. Maybe I should extract them out....

One caveat is constructors, though. Your proxied class isn't guaranteed 
a default constructor. You have to use, as I recall, 
ParameterTypeTuple!(T._ctor) to get the arguments, and supply a 
constructor of the appropriate type.

Hm. I thought I had solved that problem in my library, but now I see I 
commented that test out. Bad me |:(

> I thought maybe I could use __traits to determine all virtual functions, 
> then override them using a mixin.  I thought __traits was a compile-time 
> function, and so I thought I could create a compile-time-function that 
> returns a string defining all virtual functions.

It does, and it works. See above :)

> However, in doing so I find that the function does not work correctly, and 
> in addition, the argument to __traits for isVirtualFunction does not take a 
> string, but the result of __traits allMembers is an array of strings.  I 
> think it would be more useful if isVirtualFunction and the other isXX would 
> take either a string or the direct statement.  For example:
> 
> __traits(isVirtualFunction, "A.foo")
> would be the same as:
> __traits(isVirtualFunction, A.foo)

class A {
    final void foo ();
    int foo (int i);
}

What to return?
__traits(isVirtualFunction, A.foo) is ambiguous as well. I don't 
recommend using it, and I don't use it.

> Then I could do:
> 
> foreach(x; __traits(allMembers, A))
>     if(__traits(isVirtualfunction, "A." ~ x))
>         // append to string that redefines virtual function.

You can't foreach an array at compile time, and __traits(allMembers) 
returns an array. You can index an array at compile time, but again, you 
can't use a while loop at compile time.

You have to use recursion.

Eventually, static foreach should be able to do this. Or you can bug 
Walter about changing allMembers to return a tuple of strings.

> Second, the mixin doesn't work.  I hard-coded the function to output the 
> string I was trying to build.  Therefore, the compiler should be able to 
> execute the method in compile time, and pre-determine the string to return. 
> But the mixin just defines the function name that I am calling as a member. 
> i.e., I define my function above as:
> 
> string redefFunctions(T)();
> 
> and my mixin in the class is:
> 
> mixin(redefFunctions!(A)());
> 
> But when I build my class, there is a member redefFunctions!(A) instead of 
> the list of virtual functions I expected to override.

Not sure what the problem there is. If you omit the parentheses around 
the template method call, you'll definitely get the result you describe 
(that had me hung up for a bit), but your example has the parentheses.

> Any ideas?  Is there another way this will work?  If not, is it possible to 
> make it so it would work :) ?
> 
> -Steve 
> 
> 

Good luck!



More information about the Digitalmars-d mailing list