On Wednesday, 11 September 2013 at 18:24:31 UTC, H. S. Teoh wrote:
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

Thanks for the idea, i have implemented something based on this and it seems to be working well.

Reply via email to