Reflection magic: function signatures
Christopher Wright
dhasenan at gmail.com
Sat Jun 30 07:28:15 PDT 2007
Hey,
I've been fooling around with the idea of creating a mocks library. The
important thing that I need to do to get that is to create functions
that can be swapped in for any functions that the mocked class or
interface has.
If I could implicitly cast primitives to objects, I could just write one
variadic function taking a series of Objects. (I'd have to write a
template to create a bunch of them that I could distinguish, but that's
a minor issue.)
If I could create functions at runtime, I could just go with runtime
everything. But that's not possible in a compiled language. (Or at
least, it'd be extremely ugly, and not widely useful, so the compiler
cruft wouldn't be worth it. In interpreted languages, the compiler cruft
is much smaller, so it's worth it.)
I could try using templates to manufacture all reasonable function
prototypes, but even assuming that I can safely and implicitly cast
everything to real or Object, that's going to be O(2**n) functions to
create to support n arguments. Moreover, that still only supports
functions of a constant length.
If I could do opImplicitCast_r and provide an argument corresponding to
the type to cast from, well, that would allow me to autobox all
arguments and just use varargs to handle everything.
opAssign isn't used for function arguments, or else Bob'd be my uncle.
As far as I can tell, I can't suss out a function signature at compile
time with the current reflection systems. Flectioned seems to require a
pointer to the function, and that won't exist until the function has
been compiled.
The best I can do is something like:
---
RandomClass mock = Mock!(RandomClass); // don't use auto or badness results
Expect.Call(&(mock.method)).Arguments!(3, some_object, 9.2f);
---
Then I'd have to use the Arguments template (provided the arguments are
CTFE-friendly) to get the types and create a valid overload. But what if
the arguments aren't valid at compile time?
---
RandomClass mock = Mock!(RandomClass); // don't use auto or badness results
Expect.Call(&(mock.method)).Overload!(int, SomeClass,
float).Arguments(3, some_object, 9.2f).ReturnType!(int).Return(4);
Mocks.Replay(); // functions are actually reassigned here
---
In this case, creating the functions should be simple enough:
---
T function (U) CreateFunction(T, U...)() {
T func(U u) { return T.init; } // probably just does first element;
need mixin
return &func;
}
---
At this point, at runtime, I have to use Flectioned to find the method
to overwrite, and I can then tell the person whether they got the mock's
signature right.
This means that the compiler can't warn the user when something goes
wrong. That's not a good thing, but I can write that code myself, if I
have to. But it delays warnings and increases time to finding errors.
Any suggestions as to finding a function signature at compile time? That
would be the best solution.
Thanks!
More information about the Digitalmars-d-learn
mailing list