January 18, 2022
Is it possible to change what parameters a function takes by flipping a -version switch?  Turns out, the answer is yes: while trying to work out a nice fix for issue 14892, I discovered the following interesting little "hack":

--------------------------------------------------------------------
import std;

version(traceFuncCalls)
{
    // Fake function from which to extract parameter tuple.
    void locusFunc(string file = __FILE__, size_t line = __LINE__,
                   string func = __FUNCTION__);

    // Bind parameter declarations to an alias
    static if (is(typeof(locusFunc) Params == __parameters))
        alias Locus = Params;
    else
        static assert(0, "Not a function");
}
else
    alias Locus = AliasSeq!();

// Optionally inject default parameters, contingent on whether we're
// compiling with -version=traceFuncCalls.
void realFunc(string someOther, int args, Locus locus) {
    if (locus.length > 0)
        writefln("Locus = %s %s %s", locus);
    else
        writeln("no locus");
}

void main() {
    realFunc("", 0); // look, ma! Automatic location tracking in callee!
}
--------------------------------------------------------------------

Compile with/without -version=traceFuncCalls to see the effect. Basically, with this -version, Locus injects the 3 default parameters into the function call to realFunc.  When *not* compiling with -version, Locus is the empty tuple, and basically erases itself from realFunc's parameter list.  So zero runtime cost is incurred: the extra parameters aren't even passed to realFunc.  Only when we compile with -version, the extra parameters will be inserted -- automatically.

This would have been a wonderful solution for the -profile=gc situation: we would have been able to inject these extra parameters into Phobos functions only when compiled with -profile=gc (I changed dmd to predefine version=D_ProfileGC in this case, so the above version test could just be changed to test for this), otherwise no extra parameters would be passed and no extra cost would be incurred.

Unfortunately, this is only a "would have been": because of the fatal flaw that the above trick does not work with template functions.  IFTI gets tripped up by the alias and is unable to match the template instantiation when the default arguments are not supplied. :-( :-(


T

-- 
I think the conspiracy theorists are out to get us...