Search code examples
dmixinstemplate-meta-programming

Mixin's names parameterization with template argument


Is it possible to generate a name for a function within a mixin template? Something like this:

mixin template Generator(string name)
{
    @property void mixin(name) pure nothrow // mixin(name) is not valid :(
    { 
            //some cool stuff here
    }
}

Solution

  • I'm hoping somebody can come up with something cleaner, but this should do what you want:

    mixin template Generator(string name)
    {
        mixin("alias " ~ name ~ " = _fun;");
        @property void _fun pure nothrow
        { 
            //some cool stuff here
        }
    }
    

    This unfortunately injects _fun into the local namespace as well, though if you use Generator more than once any calls to _fun will be rejected as ambiguous. This could be a problem if you legitimately have a function named _fun defined elsewhere.

    Although you are generating multiple _funs, the calls placed through the aliases created by Generator are not ambiguous as they refer to _fun scoped by a specific template instantiation:

    mixin Generator!"foo";
    mixin Generator!"bar";
    
    foo();  // not ambiguous, calls Generator!"foo"._fun
    bar();  // not ambiguous, calls Generator!"bar"._fun
    _fun(); // ambiguous, rejected by compiler
    

    EDIT: Just wanted to throw out another crazy idea I had:

    mixin template Generator(names ...) {
      @property void opDispatch(string s)() pure nothrow {
        foreach(name ; names) {
          static if (s == name) {
            // do stuff
          }
        }
      }
    }
    
    struct Foo {
      mixin Generator!("hello", "goodbye");
    }
    
    void main() {
      Foo foo;
    
      foo.hello;
      foo.goodbye;
    }
    

    This avoids generating a garbage _fun, but it does require that your class doesn't already define opDispatch. Furthermore, it can't be used multiple times in the same class (you can't overload the same method from different mixin templates in the same scope), you have to call it once and pass in all your names as args. This might be preferable, however, if you'd like to send in all the names in one go and don't already define opDispatch.