On Mon, Sep 09, 2013 at 10:16:42PM +0200, Gary Willoughby wrote: > Just wondered if i could pick you brains for a nice solution to > dynamically add methods to a class, paying particular attention to > overloads. I'm currently writing a mocking framework and > everything's coming along nicely and i'm wondering how to handle > replacing overloads of the mocked class. > > To create a new mocked class this is the code: > > auto mock = new Mock!Person(); > > Simple enough, mock now contains an extended class with all the > methods set to assert(false) because there are no implementations > yet. What i need to do is to add the implementations dynamically. > This is the code i propose. > > mock.addMethod("getAge", int delegate(){ > return 40; > }); > > assert(mock.getAge() == 40); > > Which i guess would be easy to implement but it doesn't handle > overloads because the method string doesn't contain enough > information to define which overload it's implementing. > > Any nice ideas what would be a nice way of supporting this? I > thought i'd ask while i have a think and get some tea. :)
One idea I have is to use the built-in "typetuples" as a way of disambiguating between different overloads. For example, something like this: // This captures the function argument type list in a form that // we can call .mangleof on. template ArgTypesWrapper(ArgTypes...) { } // This builds a unique string to identify a specific overload // based on the function name and the .mangleof of its argument // types. The key to this trick is that the .mangleof of a // template encodes its argument types, so it is unique per // combination of argument types. template FuncSignature(string funcName, ArgTypes...) { enum FuncSignature = funcName ~ ArgTypesWrapper.mangleof; } class Mock(... /* whatever you currently have here */) { // This unfortunately has to be a template function in // order to be able to capture the argument types of the // delegate in the typetuple A. This may complicate the // implementation of how you'd actually dispatch to the // overload implementation at runtime. void addMethod(R, A...)(string funcName, R delegate(A...) dg) { string overloadName = FuncSignature!(funcName, A); // Now overloadName should be a unique string // representing that particular combination of // function name and argument types, i.e., it's // a function signature. So you can use it to // identify which overload is which. } } T -- Meat: euphemism for dead animal. -- Flora