<div class="gmail_quote">On Tue, May 29, 2012 at 3:59 PM, Dmitry Olshansky <span dir="ltr"><<a href="mailto:dmitry.olsh@gmail.com" target="_blank">dmitry.olsh@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I'm reiterating prior info on the subject and provide some motivating examples. For those convinced of necessity of virtual function templates already - skip to the bottom ;)<br>
<br>
Ultimately template is a way to use the same source code for multiple entities (typically called instantiations).<br>
In the light of the above simple definition it's painfully obvious that if functions generated by template are final vs virtual is completely separate orthogonal matter.<br>
The fact that templates are final is rather a happenstance,<br>
"it's 'cause it's too hard, lad" kind of thing.<br>
<br>
The fundamental problem is that given an interface<br>
interface I<br>
{<br>
        TA funcA();<br>
        TB funcB();<br>
        TC funcC();<br>
        ...<br>
}<br>
<br>
compiler needs to plot _final_ layout of a v-table so that separate compilation works without hassle. (there are possible ways around it, though non-trivial and breaking current toolchains).<br>
<br>
Now since even constrained template technically can accommodate infinite number of instantiations it sure becomes problematic.<br>
<br>
But surely the template below has exactly X instantiations,<br>
since there is only X operators in the whole D language that are ever overloadable, X being constant (sorry didn't care to count).<br>
<br>
interface Matrix<br>
{<br>
        void opOpAssign(string op)(Matrix rhs);<br>
}<br>
<br>
And this one is even down to 3:<br>
<br>
interface Matrix<br>
{<br>
        void opOpAssign(string op)(Matrix rhs)<br>
        if(op == "+" || op == "-" || op == "*");<br>
}<br>
<br>
Of course, having compiler to deduce these kind of special cases can be described as a fragile hack at best. Thus a more clean and general solution is proposed.<br>
<br>
Before moving on to syntax and the feature itself. Another motivating example to illustrate a need for virtual functions to be templates.<br>
Though I'm you know a lot of uses cases as well, so feel free to skip it.<br>
<br>
Suppose you define Set as interface for sets, and provide some implementations of it like BitSet, HashSet, TreeSet, SparceSet.<br>
<br>
Now we are back to operator overloading, some might argue that having final operators is enough, it's not:<br>
<br>
interface Set(V, K)<br>
{<br>
        V get(K key);<br>
        void put(V value, K key);<br>
        void remove(K key);<br>
        //even opApply won't save us ;)<br>
        int opApply(scope delegate(K, V));<br>
        <br>
        void opOpAssign(string op)(Set rhs)<br>
        {<br>
                <br>
                //foreach(k, v; rhs)<br>
                //      remove(k);<br>
                //Okay, now try to be efficient, punk !<br>
                ...<br>
        }<br>
}<br>
<br>
It's immediately obvious that doing low-level operations via high-level primitives is no good. Certain combination of sets are obviously can be done faster. And for instance 2 small enough bitsets can be merged in a blink of an eye, (similar things for sparse set). And nobody is willing to give up speed nor polymorphism.<br>

<br>
(e.g. Set & Set should use the best overload for '&' for concrete sets at hand == virtual operator).<br>
<br>
The only current way is forwarding to virtual methods and that may work. Though templates and new operator overloading in particular aim to reduce amount of repetition and boilerplate.<br>
<br>
<br>
Enough of talk, to the proposal, synopsis is to enhance template declaration:<br>
<br>
T func(string id, T, Args...)(...)<br>
        if( ... ) //optional<br>
        for(    //optional<br>
                id : "a", "b", "c";<br>
                T: double, float;<br>
                Args : (int, int), (uint, int), (int, uint);<br>
        )//syntax debatable, 'for' is not ;)<br>
<br>
It would then instantate all of possible overloads immediately in this particular module.  (another use case for it is explicit instantiation for shared libraries)<br>
<br>
If it happens to be inside of class/interface the by default all of overloads would work as virtual.<br>
<br>
Other then this for implies the following if condition ANDed together to existing if clause if any:<br>
.... & (<br>
(id == "a" || id == "b" || id == "c") &&<br>
(is(T == double)|| is(T == float)) &&<br>
(<br>
                (is(Args[0] == int) && is(Args[1]==int))<br>
        ||      (is(Args[0] == uint) && is(Args[1]==int))<br>
        ||      (is(Args[0] == int) && is(Args[1]==uint))<br>
<br>
)<br>
<br>
)<br>
A remarkable boilerplate, underlines the fact that trying to have compiler to deduce all types from it for you is not realistic in general case.<br>
<br>
Of course the coma separated typelists can be constructed via meta-programming. In fact all tuples should be flattened (as is everywhere else).<br>
<br>
And that's it, so new 'for' clause for templates does:<br>
        - explicitly instantes entities, ensuring bounded number of instantiations (makes virtual possible)<br>
        - provides alternative sugar for 'if' syntax<br>
        - fits with the rest of language, via typetuple and meta-programming<br>
        - allows simple techniques to curb down accidental duck-typing<span class="HOEnZb"><font color="#888888"><br>
<br>
-- <br>
Dmitry Olshansky<br>
</font></span></blockquote></div><br>This is a really awesome idea! Not only does it solve a lot of problems, it also looks very intuitive and doesn't break existing code. If D was the first language to have virtual template methods, that would be a huge credit to the language!<div>
+1!</div><div><div><div><br></div>-- <br>Bye,<br>Gor Gyolchanyan.<br>
</div></div>