Function refract

Return a Function object that captures all the aspects of fun, using the value of localName to represent the return and parameter types, and the UDAs. Set the Function's overloadIndex property to index, or to -1 if it is not specified.

Function refract(alias fun, string localName, int overloadIndex = -1)()
if (is(typeof(fun) == function));

The localName parameter is, in general, *not* the function name. Rather, it is a compile-time expression that involves only symbols that exist in the caller's scope, for example a function alias passed as a template parameter. See

https

//stackoverflow.com/questions/32615733/struct-composition-with-mixin-and-templates/32621854#32621854 for a detailed explanation.

Parameters

NameDescription
fun a function
localName a string that represents fun in the caller's context
overloadIndex index of fun in its overload set, or -1

Example

pure @nogc int answer(lazy string question);
alias F = answer; // typically F is a template argument
static assert(
    refract!(F, "F").mixture ==
    "pure @nogc @system %s.ReturnType!(F) answer(lazy %s.Parameters!(F)[0] _0);"
    .format(__MODULE__, __MODULE__));

Example

import std.format;
import std.traits : FunctionAttribute;
import bolts.experimental.refraction;

interface GrandTour {
    pure int foo() immutable;
    @nogc @trusted nothrow ref int foo(
        out real, return ref int, lazy int) const;
    @safe shared scope void bar(scope Object);
}

class Mock(Interface) : Interface {
    static foreach (member; __traits(allMembers, Interface)) {
        static foreach (fun; __traits(getOverloads, Interface, member)) {
            mixin({
                    enum Model = refract!(fun, "fun");
                    if (is(ReturnType!fun == void)) {
                        return Model.withBody("{}").mixture;
                    } else if (Model.attributes & FunctionAttribute.ref_) {
                        return Model.withBody(q{{
                                    static %s rv;
                                    return rv;
                                }}.format(Model.returnType)).mixture;
                    } else {
                        return Model.withBody(q{{
                                    return %s.init;
                                }}.format(Model.returnType)).mixture;
                    }
                }());
        }
    }
}

GrandTour mock = new Mock!GrandTour;
real x;
int i, l;
mock.foo(x, i, l++) = 1;
assert(mock.foo(x, i, l++) == 1);
assert(l == 0);