| |
| Posted by Christopher Wright | PermalinkReply |
|
Christopher Wright
| 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!
|