Search code examples
templatesd

D template specialization in different source file


I recently asked this question about how to simulate type classes in D and suggested a way to do this using template specialization.

I discovered that D doesn´t recognize template specialization in a different source file. So I couldn´t just make a specialization in a file not included from the file where the generic function is defined. To illustrate, consider this example:

//template.d
import std.stdio;
template Generic(A) {
  void sayHello() {
    writefln("Generic");
  }
}

void testTemplate(A)() {
    Generic!A.sayHello();
}


//specialization.d
import std.stdio;
import Template;

template Generic(A:int) {
  void sayHello() {
      writefln("only for ints");
  }
}

void main() {
    testTemplate!int();
}

This code prints "generic" when I run it. So I´m asking whether there is some good workaround, so that the more specialized form can be used from the algorithm.

The workaround I used in the question about Type classes was to mixin the generic functions after importing all files with template specialization, but this is somewhat ugly and limited.

I heard c++1x will have extern templates, which will allow this. Does D have a similar feature?


Solution

  • I think I can give a proper answer to this question. No.

    What you are trying to do is highjack the functionality of template.d (also case should match on file and import Template, some operating systems it matters). Consider:

    // template.d
    ...
    
    // spezialisation.d
    import std.stdio;
    import template;
    
    void main() {
        testTemplate!int();
    }
    

    Now someone updates the code:

    // specialization.d
    import std.stdio;
    import template;
    import helper;
    
    void main() {
        testTemplate!int();
        getUserData();
    }
    

    Perfect right? well inside helper:

    // helper.d
    getUserData() { ... }
    
    
    template Generic(A:int) {
        A placeholder; //...
    }
    

    You have now changed the behavior of specialization.d just from an import and in fact this would fail to compile as it can not call sayHello. This highjack prevention does have its issues. For example you may have a function which takes a Range, but the consumer of your library can not pass an array unless your library imports std.array since this is where an array is "transformed" into a range.

    I do not have a workaround for your problem.

    Michal's comment provides a solution to the second form of highjacking, where say specialization.d tried to highjack getUserData

    // specialization.d
    import std.stdio;
    import template;
    import helper;
    
    alias helper.getUserData getUserData;
    
    string getUserData(int num) { ... }
    
    void main() {
        testTemplate!int();
        getUserData();
    }