On Wednesday, 5 March 2014 at 02:28:00 UTC, Nick Sabalausky wrote:
On 3/3/2014 5:35 PM, Chris wrote:

Maybe I'm a bit too philosophical about this. But consider the following
(made up) case:

struct MyTemp(T) {
    // ...
    T add(T a, T b) {
        if (a is string && b is string) {
              return a~b;  // or return a~"+"~b; or whatever
        } else if (a is integer && a is integer) {
              return a+b;
        }
    }
}

I don't know if this can be considered a "pure" template. It is a template of sorts, but the type specialization in the function add makes
it a watered-down template,

Any useful template function already works that way. The mere + operator is *not* one single operation, but a whole category of opcodes which are chosen based on the operand's type. Thus, + can be thought of as a built-in template that [roughly] does this:

T opPlus(T a, T b) {
    if (T is integer) {
        [asm opcode for 32-bit addition] a, b
    } else if (T is ubyte) {
        [asm opcode for 8-bit addition] a, b
    } else if (T is float) {
        [asm opcode for floating point addition] a, b
    }
}

Specialization is what makes function templates useful. Some of the specialization is explicit (static if) and some is implicit (+ operator). But without specialization (explicit or implicit), all instantiations would be identical. If all instantiations are identical, why even have a template in the first place?

Yes, this is perfectly clear to me. But the opcodes only matter to the compiler not to the programmer, i.e. the logical concept that one number (integer, float ...) is added to another remains the same. That's what I was saying.

The use of templates to avoid code duplication has been mentioned (cf. Sean Kelly's post), however real duplication is rare in specialized programs, because each function or method has it's own specialized job, else we wouldn't have them. Even if we suppose that we might want to cater for string, dchar, wchar without having to write the function three times, there might be slight differences in handling the three types so we have to fork within the template. What you are basically doing then is to pack three different functions (or the parts in which they differ) in one, at programming time (not compile time). This means you introduce three _different_ types of logic / handling mechanisms. Philosophically this is not a pure template, imo. The question is where does it end? Can you turn the whole program into one big template that handles all the different types and types of logic? (Exaggerating :-) The example I showed above is maybe not so far fetched add(int, int) and add(string, string).

The points you made above about OOP are very good and I'm increasingly unhappy with OOP's limitations. However, turning to templates I find myself stuck sometimes too, and I don't feel good about "compromising" a template by using too many if's for different types or introducing new logic that should actually go into a separate function / method. I'm really interested in different approaches like templates and entities, especially if they help optimizing code for processors and memory. However, I sometimes think that in Software development we always hit the same wall, whether we go from assembly to C, to OOP, to templates. The wall is that every real world program is highly unique and specialized and abstraction goes only so far.

One good use for templates, I figure, would be writing an interpreter for a scripting or DSL. As in:

greeting = "Hello, " + "world!";
result = 1 + 1;

greeting = add(string, string)
result = add(int, int)

Reply via email to