www.digitalmars.com         C & C++   DMDScript  

D - Serious deficiencies in template mechanism

reply Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Hi there,

I've just recently come upon the D language and was captured right away by 
it. Of all those programming languages I've found over the years, this 
definitely is one of the most promising!

Anyway, the template mechanism has a number of deficiencies that makes it 
drop far behind that of C++. To those, who have never worked with stuff 
like the "expression template" method, this will look like minor details, 
but after implementing my own matrix library in C++ using that method, I 
definitely have come to realize the real power that lies behind the 
template concept in C++.

Two examples of what is possible in C++, which I could not find in D:

-------------------------
* Templated functions - allowing stuff like:

        template <typename T>
        T special_addition(T a,T b) { ... }

i.e. a function that takes two arguments of an arbitrary -- but identical -- 
type. Of course, the concept goes far beyond that and is absolutely 
indispensible in many cases.

-------------------------
* Integers as template arguments:

        template <int N>
        class Vector {
                double data[N];
        };

making Vector<2> a different type than Vector<3>, allowing stuff like direct 
vector or matrix manipulations via operators with complete type checking. 
(Going far beyond the simple possibilities of direct array manipulations in 
D.)

-------------------------
The one thing that I dislike most about C++ templates, and which has been 
carried over to D as well, is, that template parameters are not typed. I.e.
if I have:
        template <typename T>
        class Test {
                static T add(T a,T b) { return a + b; } /* X */
        };

        bool foo() {
                return Test<bool>::add(true,false); /* Y */
        };
the compiler actually complains about line /*X*/ which is absolutely 
correct, instead of telling the user that Test simply should not be 
instatiated with bool. Now if Test is somewhere deep within a library, the 
application programmer may get a huge bunch of error messages looking like 
a bug somewhere in the library, even though, the actual error was simply 
the wrong instatiation of a template.

Solution to this would be something like interfaces in D, specifying a set 
of capabilities of a type (be it a class or a predefined type), and the 
possibility to restrict parameters in a template definition to such an 
interface.
-------------------------

Now, this was just a rough sketch of what I found to be missing in D making 
it seriously fall back behind C++. It is nothing about philosophy or 
far-fetched theory, but just plain experience after many hours of digging 
into the depths of C++ templates.

Really bringing anything of this power into D would probably mean a redesign 
of large parts of the template and interface mechanism. It would also mean 
quite a bit of research and genious in language design. The mechanisms of 
expression templates are still quite new and much work is yet to be done to 
really understand the basic principles behind it.

Anyhow: unless this power is somehow carried over from C++, the language D 
can not seriously aim at measuring up with its ancestor.

Anyone interested in that whole topic, best start reading at
        http://www.oonumerics.org
perhaps starting out on blitz++ for the moment.
(I've done my own, smaller and simpler library, but it's hardly documented 
at all, so it is not yet a good starting point...)

Ciao,
Nobbi
Jan 15 2003
next sibling parent reply Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
I guess, my remark directly collides with the message "C and/or C++ in D" by 
Ben Woodhead from yesterday, therefore an additional remark:

Everything I mentioned, is, of course somehow possible to be done in D. The 
one crucial point simply is PERFORMANCE. What makes templates in C++ such a 
powerful tool in C++ is not, that they allow stuff impossible before. They 
do not even make life any more comfortable (quite in the contrary, they 
make life awfully complicated!!) Anyhow:

        They allow much of the work to be done at compile time!

I you don't want to worry about performance, simply ignore this whole topic.

Anyhow, in numerical computation, where performance often is one of the most 
crucial goals, expression templates seem to be the only way so far to allow 
the full expressiveness of object orientated languages without a huge 
performance penalty. Thousands of programmers in the numerical field still 
use Fortran 77 simply because of its unbeaten performance and it was not 
until the discovery of expression templates, that C++ could close up with 
that speed.

Anyhow: the suggestion of allowing to restrict template parameter types is 
probably independant of the other extensions, and I would seriously advise 
the language designers to consider this unless they want to make using 
template libraries a pain to anyone.

Ciao,
Nobbi
Jan 15 2003
parent reply Daniel Yokomiso <Daniel_member pathlink.com> writes:
In article <b03ehf$2muu$1 digitaldaemon.com>, Norbert Nemec says...
I guess, my remark directly collides with the message "C and/or C++ in D" by 
Ben Woodhead from yesterday, therefore an additional remark:

Everything I mentioned, is, of course somehow possible to be done in D. The 
one crucial point simply is PERFORMANCE. What makes templates in C++ such a 
powerful tool in C++ is not, that they allow stuff impossible before. They 
do not even make life any more comfortable (quite in the contrary, they 
make life awfully complicated!!) Anyhow:

        They allow much of the work to be done at compile time!

I you don't want to worry about performance, simply ignore this whole topic.

Anyhow, in numerical computation, where performance often is one of the most 
crucial goals, expression templates seem to be the only way so far to allow 
the full expressiveness of object orientated languages without a huge 
performance penalty. Thousands of programmers in the numerical field still 
use Fortran 77 simply because of its unbeaten performance and it was not 
until the discovery of expression templates, that C++ could close up with 
that speed.

Anyhow: the suggestion of allowing to restrict template parameter types is 
probably independant of the other extensions, and I would seriously advise 
the language designers to consider this unless they want to make using 
template libraries a pain to anyone.

Ciao,
Nobbi

Hi, Expression templates aren't the only way of achieving performance in "correct" OO systems. In a good type system we can do more agressive inlining of operations, reduce the need for dynamic dispatch, do strictness analysis to ignore partial unnecessary results, do loop unrolling, etc.. All of these are good in every piece of code, not just in some particular mechanism. The problem with expression templates is that they require someone (the library writer) to know how to write code with optimization hints. In C++ template syntax is almost a language of its own. In Common Lisp macro expansion (which can do anything expression templates do and more) gives you similar performance, but the syntax is much more similar to Common Lisp. Scheme also provides a expressive and simple to use macro system. Best regards, Daniel Yokomiso.
Jan 16 2003
parent reply Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Daniel Yokomiso wrote:
 Hi,
 
 Expression templates aren't the only way of achieving performance in
 "correct" OO systems. In a good type system we can do more agressive
 inlining of operations, reduce the need for dynamic dispatch, do
 strictness analysis to ignore partial unnecessary results, do loop
 unrolling, etc.. All of these are good in every piece of code, not just in
 some particular mechanism. The problem with expression templates is that
 they require someone (the library writer) to know how to write code with
 optimization hints. In C++ template syntax is almost a language of its
 own. In Common Lisp macro expansion (which can do anything expression
 templates do and more) gives you similar performance, but the syntax is
 much more similar to Common Lisp. Scheme also provides a expressive and
 simple to use macro system.

Very true. Al these parts have to play together. As far as I can see it, the main advantage of expression templates is, just as you say, that C++ templates are a language on their own, allowing a library author to do all kinds of optimizations and complex decisions at compile time. The only use for them is in heavily optimized libraries - otherwise the effort for writing them will never be justified. Anyhow, in the quest for performance one always has to consider all the bottlenecks, and in the main field of usage for expression templates of C++ - i.e. array calculations - one of the main bottlenecks is the need for temporary copies. And this can only be solved by either implementing far more advanced array manipulations in D directly or give the library authors the tools necessary to do their best. Ciao, Nobbi
Jan 17 2003
parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>
escreveu na mensagem news:b08ums$2p3a$1 digitaldaemon.com...
 Daniel Yokomiso wrote:
 Hi,

 Expression templates aren't the only way of achieving performance in
 "correct" OO systems. In a good type system we can do more agressive
 inlining of operations, reduce the need for dynamic dispatch, do
 strictness analysis to ignore partial unnecessary results, do loop
 unrolling, etc.. All of these are good in every piece of code, not just


 some particular mechanism. The problem with expression templates is that
 they require someone (the library writer) to know how to write code with
 optimization hints. In C++ template syntax is almost a language of its
 own. In Common Lisp macro expansion (which can do anything expression
 templates do and more) gives you similar performance, but the syntax is
 much more similar to Common Lisp. Scheme also provides a expressive and
 simple to use macro system.

Very true. Al these parts have to play together. As far as I can see it,

 main advantage of expression templates is, just as you say, that C++
 templates are a language on their own, allowing a library author to do all
 kinds of optimizations and complex decisions at compile time. The only use
 for them is in heavily optimized libraries - otherwise the effort for
 writing them will never be justified.

 Anyhow, in the quest for performance one always has to consider all the
 bottlenecks, and in the main field of usage for expression templates of

 - i.e. array calculations - one of the main bottlenecks is the need for
 temporary copies. And this can only be solved by either implementing far
 more advanced array manipulations in D directly or give the library

 the tools necessary to do their best.

 Ciao,
 Nobbi

We can add more powerful array operations if they became safer: http://www.sys.uea.ac.uk/~jrwg/Sisal/ This may solve the problems Expression Templates try to solve... --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 11/1/2003
Jan 17 2003
parent reply Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Daniel Yokomiso wrote:
     We can add more powerful array operations if they became safer:
 http://www.sys.uea.ac.uk/~jrwg/Sisal/ This may solve the problems
 Expression Templates try to solve...

You may also take a look at SAC (Single Assignment C) at http://www.informatik.uni-kiel.de/~sacbase/ which claims to the the official successor of Sisal. Anyway: Both languages are tailored towards high-performance numerical computing. No way to even consider taking D, which is explicitely designed to be a general purpose language in that direction. And just trying to pick bits from them will not buy us much.
Jan 20 2003
parent "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>
escreveu na mensagem news:b0h0gs$159b$1 digitaldaemon.com...
 Daniel Yokomiso wrote:
     We can add more powerful array operations if they became safer:
 http://www.sys.uea.ac.uk/~jrwg/Sisal/ This may solve the problems
 Expression Templates try to solve...

You may also take a look at SAC (Single Assignment C) at http://www.informatik.uni-kiel.de/~sacbase/ which claims to the the official successor of Sisal. Anyway: Both languages are tailored towards high-performance numerical computing. No way to even consider taking D, which is explicitely designed to be a general purpose language in that direction. And just trying to pick bits from them will not buy us much.

SAC is also very nice too. IMO their array semantics could be extended to D without changing much of D's nature as general purpose programming language. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 10/1/2003
Jan 20 2003
prev sibling next sibling parent reply Theodore Reed <rizen surreality.us> writes:
On Wed, 15 Jan 2003 11:34:14 +0100
Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>
wrote:

 * Templated functions - allowing stuff like:
 
         template <typename T>
         T special_addition(T a,T b) { ... }
 
 i.e. a function that takes two arguments of an arbitrary -- but
 identical -- type. Of course, the concept goes far beyond that and is
 absolutely indispensible in many cases.

I thought this was possible: template special (T) { T addition(T a, T b) { ... } } From what I under stand, there isn't anything you can't templatize, although your int example is interesting. I didn't even know C++ templates could do that. -- Theodore Reed (rizen/bancus) -==- http://www.surreality.us/ ~OpenPGP Signed/Encrypted Mail Preferred; Finger me for my public key!~ "Those who hammer their guns into plowshares will plow for those who do not." -- Thomas Jefferson
Jan 15 2003
parent Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Theodore Reed wrote:

 On Wed, 15 Jan 2003 11:34:14 +0100
 Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>
 wrote:
 
 * Templated functions - allowing stuff like:
 
         template <typename T>
         T special_addition(T a,T b) { ... }
 
 i.e. a function that takes two arguments of an arbitrary -- but
 identical -- type. Of course, the concept goes far beyond that and is
 absolutely indispensible in many cases.

I thought this was possible: template special (T) { T addition(T a, T b) { ... } } From what I under stand, there isn't anything you can't templatize, although your int example is interesting. I didn't even know C++ templates could do that.

OK, but as I understand it, this needs to be called like: x = special(int).addition(3,5); whereas in C++, a call to addition(3,5) does implicit instatiation. Don't know, though, whether that would be a fundamental problem.
Jan 17 2003
prev sibling next sibling parent reply "Walter" <walter digitalmars.com> writes:
Comments embedded...

"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> wrote
in message news:b03d7n$2m9r$1 digitaldaemon.com...
 Hi there,

 I've just recently come upon the D language and was captured right away by
 it. Of all those programming languages I've found over the years, this
 definitely is one of the most promising!

 Anyway, the template mechanism has a number of deficiencies that makes it
 drop far behind that of C++. To those, who have never worked with stuff
 like the "expression template" method, this will look like minor details,
 but after implementing my own matrix library in C++ using that method, I
 definitely have come to realize the real power that lies behind the
 template concept in C++.

 Two examples of what is possible in C++, which I could not find in D:

 -------------------------
 * Templated functions - allowing stuff like:

         template <typename T>
         T special_addition(T a,T b) { ... }

 i.e. a function that takes two arguments of an arbitrary -- but

 type. Of course, the concept goes far beyond that and is absolutely
 indispensible in many cases.

This does work in D, as Theodore's example shows.
 -------------------------
 * Integers as template arguments:

         template <int N>
         class Vector {
                 double data[N];
         };

 making Vector<2> a different type than Vector<3>, allowing stuff like

 vector or matrix manipulations via operators with complete type checking.
 (Going far beyond the simple possibilities of direct array manipulations

 D.)

This is probably going to have to be added to D. Nobody seems to like the alternative mechanism I proposed <g>.
 -------------------------
 The one thing that I dislike most about C++ templates, and which has been
 carried over to D as well, is, that template parameters are not typed.

 if I have:
         template <typename T>
         class Test {
                 static T add(T a,T b) { return a + b; } /* X */
         };

         bool foo() {
                 return Test<bool>::add(true,false); /* Y */
         };
 the compiler actually complains about line /*X*/ which is absolutely
 correct, instead of telling the user that Test simply should not be
 instatiated with bool. Now if Test is somewhere deep within a library, the
 application programmer may get a huge bunch of error messages looking like
 a bug somewhere in the library, even though, the actual error was simply
 the wrong instatiation of a template.

 Solution to this would be something like interfaces in D, specifying a set
 of capabilities of a type (be it a class or a predefined type), and the
 possibility to restrict parameters in a template definition to such an
 interface.
 -------------------------

A good point. Error messages are always a pain with templates.
 Now, this was just a rough sketch of what I found to be missing in D

 it seriously fall back behind C++. It is nothing about philosophy or
 far-fetched theory, but just plain experience after many hours of digging
 into the depths of C++ templates.

 Really bringing anything of this power into D would probably mean a

 of large parts of the template and interface mechanism. It would also mean
 quite a bit of research and genious in language design. The mechanisms of
 expression templates are still quite new and much work is yet to be done

 really understand the basic principles behind it.

 Anyhow: unless this power is somehow carried over from C++, the language D
 can not seriously aim at measuring up with its ancestor.

 Anyone interested in that whole topic, best start reading at
         http://www.oonumerics.org
 perhaps starting out on blitz++ for the moment.
 (I've done my own, smaller and simpler library, but it's hardly documented
 at all, so it is not yet a good starting point...)

 Ciao,
 Nobbi

Jan 15 2003
next sibling parent Ilya Minkov <midiclub 8ung.at> writes:
 
 This is probably going to have to be added to D. Nobody seems to like the
 alternative mechanism I proposed <g>.
 

Jan 15 2003
prev sibling parent reply Daniel Yokomiso <Daniel_member pathlink.com> writes:
In article <b04fq8$8t8$1 digitaldaemon.com>, Walter says...

[snip]
 -------------------------
 * Integers as template arguments:

         template <int N>
         class Vector {
                 double data[N];
         };

 making Vector<2> a different type than Vector<3>, allowing stuff like

 vector or matrix manipulations via operators with complete type checking.
 (Going far beyond the simple possibilities of direct array manipulations

 D.)

This is probably going to have to be added to D. Nobody seems to like the alternative mechanism I proposed <g>.

[snip] Hi, I'm glad you're considering adding this to the language. Which kind of value parameters will be possible: just integers or any kind of value? Also there's another problem with current template syntax. We can't define templates which define templatized methods. E.g. a List(T) class with a method List(U) map(U (*operation)(T)). This is a very good thing to have. C# generics proposal allows definition of generic classes with generic methods, and you have to instantiate the generic method when you use it, not when you instantiate the generic class. This, together with integer template parameters will allow D to have type-safe unit classes for scientific programming: // Using CGS unit system public template class Unit(int C, int G, int S) { private double _value; public this(double value) { this._value = value; } public double value() { return this._value; } public Unit(C, G, S) mul(int other) { return new Unit(C, G, S)(value() * other); } public template Unit(C - X, G - Y, S - Z) div(Unit(X, Y, Z) other) { return new Unit(C - X, G - Y, S - Z)(value() / other.value()); } } alias Unit(1, 0, 0) Length; alias Unit(0, 1, 0) Mass; alias Unit(0, 0, 1) Time; alias Unit(1, 0, -1) Speed; alias Unit(2, 1, 2) Energy; const Length metre = new Length(100); const Length second = new Time(1); const Length kilogram = new Mass(1000); const Speed c = 299792458 * metre / second; Mass m = 100 * kilogram; Energy e; e = m * c * c; Nice isn't it? Some issues about invalid instantiation can happen if the code uses variables to define dimensions, but I think limiting dimensions to be constant isn't a big problem. I don't think the compiler complexity is a burden when we compare it to the benefits it brings. Best regards, Daniel Yokomiso.
Jan 16 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Daniel Yokomiso" <Daniel_member pathlink.com> wrote in message
news:b06sg3$1m3l$1 digitaldaemon.com...
 I'm glad you're considering adding this to the language. Which kind of

 parameters will be possible: just integers or any kind of value?

Probably just integer constants. I like to be conservative on adding these kinds of things until a real need is clear.
 Also there's another problem with current template syntax. We can't define
 templates which define templatized methods. E.g. a List(T) class with a

 List(U) map(U (*operation)(T)). This is a very good thing to have.

I don't understand.
 C# generics
 proposal allows definition of generic classes with generic methods, and

 to instantiate the generic method when you use it, not when you

 generic class. This, together with integer template parameters will allow

 have type-safe unit classes for scientific programming:

 // Using CGS unit system
 public template class Unit(int C, int G, int S) {
 private double _value;
 public this(double value) {
 this._value = value;
 }
 public double value() {
 return this._value;
 }
 public Unit(C, G, S) mul(int other) {
 return new Unit(C, G, S)(value() * other);
 }
 public template Unit(C - X, G - Y, S - Z) div(Unit(X, Y, Z) other) {
 return new Unit(C - X, G - Y, S - Z)(value() / other.value());
 }
 }

 alias Unit(1, 0, 0) Length;
 alias Unit(0, 1, 0) Mass;
 alias Unit(0, 0, 1) Time;
 alias Unit(1, 0, -1) Speed;
 alias Unit(2, 1, 2) Energy;

 const Length metre = new Length(100);
 const Length second = new Time(1);
 const Length kilogram = new Mass(1000);
 const Speed c = 299792458 * metre / second;

 Mass m = 100 * kilogram;
 Energy e;

 e = m * c * c;

 Nice isn't it? Some issues about invalid instantiation can happen if the

 uses variables to define dimensions, but I think limiting dimensions to be
 constant isn't a big problem. I don't think the compiler complexity is a

 when we compare it to the benefits it brings.

 Best regards,
 Daniel Yokomiso.

Jan 18 2003
next sibling parent Norbert Nemec <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Walter wrote:

 "Daniel Yokomiso" <Daniel_member pathlink.com> wrote:
 I'm glad you're considering adding this to the language. Which kind of
 value parameters will be possible: just integers or any kind of value?

Probably just integer constants. I like to be conservative on adding these kinds of things until a real need is clear.

Hopefully bits and enums as well?
Jan 18 2003
prev sibling parent "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Walter" <walter digitalmars.com> escreveu na mensagem
news:b0b9dm$165s$1 digitaldaemon.com...
 "Daniel Yokomiso" <Daniel_member pathlink.com> wrote in message
 news:b06sg3$1m3l$1 digitaldaemon.com...
 I'm glad you're considering adding this to the language. Which kind of

 parameters will be possible: just integers or any kind of value?

Probably just integer constants. I like to be conservative on adding these kinds of things until a real need is clear.
 Also there's another problem with current template syntax. We can't


 templates which define templatized methods. E.g. a List(T) class with a

 List(U) map(U (*operation)(T)). This is a very good thing to have.

I don't understand.

We define a template for a generic list class: template TList(T) { class List { T first(); List rest(); T get(int index); void set(int index, T value); int length(); List slice(int start, int afterEnd); List filter(boolean (*predicate)(T)); } } With all needed operations. One idiom from functional programming is using a map operation to transverse data-structures using higher-order functions: Address getAddress(Employee emp) { return emp.address; } instance TList(Employee).List employees = ...; instance TList(Address).List addresses = employees.map(&getAddress); and map has a body that looks like (types ommited): map(*operation) { List result = new List(this.length()); for (int i = 0; i < this.length(); i++) { result.set(i, operation(get(i))); } return result; } If *operation is function that maps values of one type into another type. It's a higher-order function, that means a function that has other functions as parameters. But map must be generic beyond the scope of initial template instantiation, because we can instantiate a list template of ints and use mapping functions that gives lists of doubles (e.g. applying sqrt to all ints), lists of char[] (e.g. string forms of numbers) or even lists of ints (e.g. negated values). This application of functions that are templatized and introduce a second level of parametrization is useful in lots of different areas, a map function in a list type is one of the simplest form of using it. Today we have to write another template: template TMap(T, U) { instance TList(U).List ListU; instance TList(T).List ListT; ListU map(ListT list, U (*operation)(T)) { ListU result = new ListU(this.length()); for (int i = 0; i < list.length(); i++) { result.set(i, operation(list.get(i))); } return result; } } And users must always explicitly instantiate the templates and use tmap.map(list, op) instead of a simpler form list.map(op). There are functions that may be parametrized with more than one extra type parameter, so we end with lots of explicit templates. Also the additional templates must have a way to efficiently access the data from the list type, either using an external iterator, or something like that, where a generic method can access the internals of the class without penalty. As I said, C# and Java's generics proposal allows this kind of specialization. Any statically typed functional language has it too. In Java generic methods look like this: // snippet from last proposal class Seq<A> { <B> Seq<Pair<A,B>> zip(Seq<B> that) { if (this.isEmpty() || that.isEmpty()) { return new Seq<Pair<A,B>>(); } else { return new Seq<Pair<A,B>>( new Pair<A,B>(this.head, that.head), this.tail.<B>zip(that.tail)); } } } where Seq is a sequence type, and zip takes two sequences and return a sequence of pairs taken from each. I think we need this kind of functionality, or else we will be forced to written additional templates for each possible combination of parametrized methods. Also the trick I used in the last a email of making type-safe unit types (combining integer parameters and generic methods) won't be available :-( Best regards, Daniel Yokomiso. "Sometimes I think the surest sign that intelligent life exists elsewhere in the universe is that none of it has tried to contact us." - Bill Watterson --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 10/1/2003
Jan 18 2003
prev sibling parent reply Daniel Yokomiso <Daniel_member pathlink.com> writes:
Hi, 

Answers embedded.

In article <b03d7n$2m9r$1 digitaldaemon.com>, Norbert Nemec says...
Hi there,

I've just recently come upon the D language and was captured right away by 
it. Of all those programming languages I've found over the years, this 
definitely is one of the most promising!

Anyway, the template mechanism has a number of deficiencies that makes it 
drop far behind that of C++. To those, who have never worked with stuff 
like the "expression template" method, this will look like minor details, 
but after implementing my own matrix library in C++ using that method, I 
definitely have come to realize the real power that lies behind the 
template concept in C++.

Two examples of what is possible in C++, which I could not find in D:

-------------------------
* Templated functions - allowing stuff like:

        template <typename T>
        T special_addition(T a,T b) { ... }

i.e. a function that takes two arguments of an arbitrary -- but identical -- 
type. Of course, the concept goes far beyond that and is absolutely 
indispensible in many cases.

As others pointed out this is possible in D: template TAddition(T) { T special_addition(T a,T b) { ... } } But we need to name the template.So usually D templates pack a set of related functions.
-------------------------
* Integers as template arguments:

        template <int N>
        class Vector {
                double data[N];
        };

making Vector<2> a different type than Vector<3>, allowing stuff like direct 
vector or matrix manipulations via operators with complete type checking. 
(Going far beyond the simple possibilities of direct array manipulations in 
D.)

As Walter pointed out this will get in D. That is a Good Thing :-)
-------------------------
The one thing that I dislike most about C++ templates, and which has been 
carried over to D as well, is, that template parameters are not typed. I.e.
if I have:
        template <typename T>
        class Test {
                static T add(T a,T b) { return a + b; } /* X */
        };

        bool foo() {
                return Test<bool>::add(true,false); /* Y */
        };
the compiler actually complains about line /*X*/ which is absolutely 
correct, instead of telling the user that Test simply should not be 
instatiated with bool. Now if Test is somewhere deep within a library, the 
application programmer may get a huge bunch of error messages looking like 
a bug somewhere in the library, even though, the actual error was simply 
the wrong instatiation of a template.

Solution to this would be something like interfaces in D, specifying a set 
of capabilities of a type (be it a class or a predefined type), and the 
possibility to restrict parameters in a template definition to such an 
interface.
-------------------------

If you restrict yourself to classes, you can restrict the type parameters: template TSort(T : Comparable) { } where Comparable is a type or class. AFAIK it's valid D code, if not is should ;-) . There's some info at http://www.digitalmars.com/d/template.html under Argument Deduction section. I don't think there's any reason for the compiler to always complain about line /*X*/, instead of saying: Template instantiation at line /*Y*/ is invalid because of /*X*/ requirement in template body. Systems with type inference algorithms usually provide some intelligent error messages. There's also some papers about giving intelligent error messages in type inference algorithms.
Now, this was just a rough sketch of what I found to be missing in D making 
it seriously fall back behind C++. It is nothing about philosophy or 
far-fetched theory, but just plain experience after many hours of digging 
into the depths of C++ templates.

Really bringing anything of this power into D would probably mean a redesign 
of large parts of the template and interface mechanism. It would also mean 
quite a bit of research and genious in language design. The mechanisms of 
expression templates are still quite new and much work is yet to be done to 
really understand the basic principles behind it.

Anyhow: unless this power is somehow carried over from C++, the language D 
can not seriously aim at measuring up with its ancestor.

IIRC D's ancestor is C. C++ is just an older cousin ;-)
Anyone interested in that whole topic, best start reading at
        http://www.oonumerics.org
perhaps starting out on blitz++ for the moment.
(I've done my own, smaller and simpler library, but it's hardly documented 
at all, so it is not yet a good starting point...)

Ciao,
Nobbi

C++ template mechanism is very powerful, but almost impossible to get right. Walter writes C++ compiler writes since the beginning of C++, so he knows about the pitfalls of template mechanism. All these issues about template are causes of several threads in this newsgroup (check the archives where lots of people, including me, argue for a better template mechanism). Blitz++ does a very good usageof templates, I like particularly the tensor notation. But it carries a 750 page language standard behind it, defining the mechanism it uses. Walter wants something better, we just have to keep throwing him good ideas and critics. Best regards, Daniel Yokomiso.
Jan 16 2003
parent reply Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Daniel Yokomiso wrote:

 In article <b03d7n$2m9r$1 digitaldaemon.com>, Norbert Nemec says...
-------------------------
The one thing that I dislike most about C++ templates, and which has been
carried over to D as well, is, that template parameters are not typed.
I.e. if I have:
        template <typename T>
        class Test {
                static T add(T a,T b) { return a + b; } /* X */
        };

        bool foo() {
                return Test<bool>::add(true,false); /* Y */
        };
the compiler actually complains about line /*X*/ which is absolutely
correct, instead of telling the user that Test simply should not be
instatiated with bool. Now if Test is somewhere deep within a library, the
application programmer may get a huge bunch of error messages looking like
a bug somewhere in the library, even though, the actual error was simply
the wrong instatiation of a template.

Solution to this would be something like interfaces in D, specifying a set
of capabilities of a type (be it a class or a predefined type), and the
possibility to restrict parameters in a template definition to such an
interface.

If you restrict yourself to classes, you can restrict the type parameters: template TSort(T : Comparable) { } where Comparable is a type or class. AFAIK it's valid D code, if not is should ;-) .

I'm not sure whether that should really be the correct way to say it. Otherwise template X(T:T[]) {} would mean that T has to be a subtype of T[], which is complete nonsense. It is hard to name the actual meaning of the ":", but it definitely is not "subtype of". Actually, I don't have the slightest idea what would be better. Perhaps: template X(T:T < Comparable) {} as in Sather?
 I don't think there's any reason for the compiler to always
 complain about line /*X*/, instead of saying: Template instantiation at
 line /*Y*/ is invalid because of /*X*/ requirement in template body.
 Systems with type inference algorithms usually provide some intelligent
 error messages. There's also some papers about giving intelligent error
 messages in type inference algorithms.

Problem is, that in C++ code (and in D code as well), one cannot even say where the error lies. Did the library author do something illegal with the argument, or did the application programmer do a wrong instatiation? As long as there is no way to specify what capabilities the parameter types are supposed to have, even the most intelligent compiler cannot say more than: /*Y*/ seems to be wrong because of /*X*/, or even more nested error messages. In a case of 10 nested instantiations, the actual error might be located at any level. And what it worse: there is no way to completely test the compilability of a template without doing all possible instantiations.
 C++ template mechanism is very powerful, but almost impossible to get
 right. Walter writes C++ compiler writes since the beginning of C++, so he
 knows about the pitfalls of template mechanism. All these issues about
 template are causes of several threads in this newsgroup (check the
 archives where lots of people, including me, argue for a better template
 mechanism). Blitz++ does a very good usageof templates, I like
 particularly the tensor notation. But it carries a 750 page language
 standard behind it, defining the mechanism it uses. Walter wants something
 better, we just have to keep throwing him good ideas and critics.

Nothing to say against that! Probably, the whole power of the C++ template mechanism was never actually planned. Actually, the fact that it hides a complete language on its own was even found by accident. And up to now, I guess nobody has really pinned down what the details are that make it so powerful. Guess it will take a good portion of genious to extract that part without carrying over all the drawbacks... Ciao, Nobbi
Jan 17 2003
next sibling parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>
escreveu na mensagem news:b08u26$2orh$1 digitaldaemon.com...
 Daniel Yokomiso wrote:

 In article <b03d7n$2m9r$1 digitaldaemon.com>, Norbert Nemec says...
-------------------------
The one thing that I dislike most about C++ templates, and which has



carried over to D as well, is, that template parameters are not typed.
I.e. if I have:
        template <typename T>
        class Test {
                static T add(T a,T b) { return a + b; } /* X */
        };

        bool foo() {
                return Test<bool>::add(true,false); /* Y */
        };
the compiler actually complains about line /*X*/ which is absolutely
correct, instead of telling the user that Test simply should not be
instatiated with bool. Now if Test is somewhere deep within a library,



application programmer may get a huge bunch of error messages looking



a bug somewhere in the library, even though, the actual error was simply
the wrong instatiation of a template.

Solution to this would be something like interfaces in D, specifying a



of capabilities of a type (be it a class or a predefined type), and the
possibility to restrict parameters in a template definition to such an
interface.

If you restrict yourself to classes, you can restrict the type


 template TSort(T : Comparable) {
 }

 where Comparable is a type or class. AFAIK it's valid D code, if not is
 should ;-) .

I'm not sure whether that should really be the correct way to say it. Otherwise template X(T:T[]) {} would mean that T has to be a subtype of T[], which is complete nonsense.

 is hard to name the actual meaning of the ":", but it definitely is not
 "subtype of". Actually, I don't have the slightest idea what would be
 better. Perhaps:
         template X(T:T < Comparable) {}
 as in Sather?

Maybe if we use the subtype operator <: from theoretical OO work. template X(T <: Comparable; U; V <: Somethingable, Otherthingable) {} with multiple constraints possible. Are multiple constraints possible in Sather? I don't remember reading about this in the docs, but I'm sure in Eiffel they aren't.
 I don't think there's any reason for the compiler to always
 complain about line /*X*/, instead of saying: Template instantiation at
 line /*Y*/ is invalid because of /*X*/ requirement in template body.
 Systems with type inference algorithms usually provide some intelligent
 error messages. There's also some papers about giving intelligent error
 messages in type inference algorithms.

Problem is, that in C++ code (and in D code as well), one cannot even say where the error lies. Did the library author do something illegal with the argument, or did the application programmer do a wrong instatiation? As long as there is no way to specify what capabilities the parameter types are supposed to have, even the most intelligent compiler cannot say more than: /*Y*/ seems to be wrong because of /*X*/, or even more nested error messages. In a case of 10 nested instantiations, the actual error might be located at any level. And what it worse: there is no way to completely test the compilability of

 template without doing all possible instantiations.

The way I see it, a template is always correct. The complete set of requirements that a type parameter must meet is in all the possible usages inside the template (all execution paths). So if the template requires your type to provide + & [] .connectToSQL() operations, it's your problem meeting this. At least until we can add operation interfaces. In current mechanisms the template determine a structural typing constraint a la OCaml methods on their parameters.
 C++ template mechanism is very powerful, but almost impossible to get
 right. Walter writes C++ compiler writes since the beginning of C++, so


 knows about the pitfalls of template mechanism. All these issues about
 template are causes of several threads in this newsgroup (check the
 archives where lots of people, including me, argue for a better template
 mechanism). Blitz++ does a very good usageof templates, I like
 particularly the tensor notation. But it carries a 750 page language
 standard behind it, defining the mechanism it uses. Walter wants


 better, we just have to keep throwing him good ideas and critics.

Nothing to say against that! Probably, the whole power of the C++ template mechanism was never actually planned. Actually, the fact that it hides a complete language on its own was even found by accident. And up to now, I guess nobody has really pinned down what the details are that make it so powerful. Guess it will take a good portion of genious to extract that

 without carrying over all the drawbacks...

 Ciao,
 Nobbi

Maybe if we ordinary folks think hard enough for sufficient time we can mimic geniality? ;-) Best regards, Daniel Yokomiso. "It is a bit embarrassing to have been concerned with the human problem all one's life and find at the end that one has no more to offer by way of advice than 'Try to be a little kinder'." - Aldous Huxley --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 11/1/2003
Jan 17 2003
next sibling parent reply Norbert Nemec <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Daniel Yokomiso wrote:
     Maybe if we use the subtype operator <: from theoretical OO work.
 
 
 template X(T <: Comparable; U; V <: Somethingable, Otherthingable) {}
 
 
 with multiple constraints possible.

 Are multiple constraints possible in Sather?

No, but you have multiple inheritance (with ingeniously simple mechanisms to avoid all the hassle of it) so you can just pull two interfaces together to a combined one.
     The way I see it, a template is always correct. The complete set of
 requirements that a type parameter must meet is in all the possible usages
 inside the template (all execution paths). So if the template requires
 your type to provide + & [] .connectToSQL() operations, it's your problem
 meeting this. At least until we can add operation interfaces. In current
 mechanisms the template determine a structural typing constraint a la
 OCaml methods on their parameters.

True, but the core of the problem really is, that you cannot specify those requirements in the interface of the template. That way, a template cannot really be separated into interface and implementation, but you (and the compiler as well) have to read the whole implementation to know the interface.
 Maybe if we ordinary folks think hard enough for sufficient time we can
 mimic geniality? ;-)

Dream on! Ingenious ideas have always suddenly sprung up from somewhere, and the hardest part always was to recognize them as such. There are probably tons of ingenious ideas hidden in the discussions of this newsgroup, but in the end it will be the responsibility of Walter to pick out the good ones. And that will always need some geniality on its own... :-)
Jan 18 2003
next sibling parent reply "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
"Norbert Nemec" <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>
escreveu na mensagem news:b0bej0$18bu$1 digitaldaemon.com...
 Daniel Yokomiso wrote:
     Maybe if we use the subtype operator <: from theoretical OO work.


 template X(T <: Comparable; U; V <: Somethingable, Otherthingable) {}


 with multiple constraints possible.

 Are multiple constraints possible in Sather?

No, but you have multiple inheritance (with ingeniously simple mechanisms

 avoid all the hassle of it) so you can just pull two interfaces together

 a combined one.

Sather provide sub and super typing operator IIRC, but it can be used to redefine the inheritance hierarchy of two different set of classes? E.g. in library A there's a method that requires something of type NumericComparable that is both Numeric and Comparable. In library B exists class C that inherits from Numeric and Comparable, but not from NumericComparable. The user of these two libraries may say that C inherits from NumericComparable too?
     The way I see it, a template is always correct. The complete set of
 requirements that a type parameter must meet is in all the possible


 inside the template (all execution paths). So if the template requires
 your type to provide + & [] .connectToSQL() operations, it's your


 meeting this. At least until we can add operation interfaces. In current
 mechanisms the template determine a structural typing constraint a la
 OCaml methods on their parameters.

True, but the core of the problem really is, that you cannot specify those requirements in the interface of the template. That way, a template cannot really be separated into interface and implementation, but you (and the compiler as well) have to read the whole implementation to know the interface.

Or rely on the intelligent and informative error messages from the compiler ;-)
 Maybe if we ordinary folks think hard enough for sufficient time we can
 mimic geniality? ;-)

Dream on! Ingenious ideas have always suddenly sprung up from somewhere,

 the hardest part always was to recognize them as such. There are probably
 tons of ingenious ideas hidden in the discussions of this newsgroup, but

 the end it will be the responsibility of Walter to pick out the good ones.
 And that will always need some geniality on its own... :-)

That's why I keep reading posts from several different sources (e.g.: comp.lang.functional, comp.compilers) and download more papers than I can read. To improve my geniality skills ;-) "Norbert Nemec" <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> escreveu na mensagem news:b0bej0$18bu$1 digitaldaemon.com...
 Daniel Yokomiso wrote:
     Maybe if we use the subtype operator <: from theoretical OO work.


 template X(T <: Comparable; U; V <: Somethingable, Otherthingable) {}


 with multiple constraints possible.

 Are multiple constraints possible in Sather?

No, but you have multiple inheritance (with ingeniously simple mechanisms

 avoid all the hassle of it) so you can just pull two interfaces together

 a combined one.

Sather provide sub and super typing operator IIRC, but it can be used to redefine the inheritance hierarchy of two different set of classes? E.g. in library A there's a method that requires something of type NumericComparable that is both Numeric and Comparable. In library B exists class C that inherits from Numeric and Comparable, but not from NumericComparable. The user of these two libraries may say that C inherits from NumericComparable too?
     The way I see it, a template is always correct. The complete set of
 requirements that a type parameter must meet is in all the possible


 inside the template (all execution paths). So if the template requires
 your type to provide + & [] .connectToSQL() operations, it's your


 meeting this. At least until we can add operation interfaces. In current
 mechanisms the template determine a structural typing constraint a la
 OCaml methods on their parameters.

True, but the core of the problem really is, that you cannot specify those requirements in the interface of the template. That way, a template cannot really be separated into interface and implementation, but you (and the compiler as well) have to read the whole implementation to know the interface.

Or rely on the intelligent and informative error messages from the compiler ;-)
 Maybe if we ordinary folks think hard enough for sufficient time we can
 mimic geniality? ;-)

Dream on! Ingenious ideas have always suddenly sprung up from somewhere,

 the hardest part always was to recognize them as such. There are probably
 tons of ingenious ideas hidden in the discussions of this newsgroup, but

 the end it will be the responsibility of Walter to pick out the good ones.
 And that will always need some geniality on its own... :-)

That's why I keep reading posts from several different sources (e.g.: comp.lang.functional, comp.compilers) and download more papers than I can read. To improve my geniality skills ;-)
Jan 18 2003
parent Norbert Nemec <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Daniel Yokomiso wrote:
 "Norbert Nemec" <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>
 Daniel Yokomiso wrote:
     Maybe if we use the subtype operator <: from theoretical OO work.


 template X(T <: Comparable; U; V <: Somethingable, Otherthingable) {}


 with multiple constraints possible.

 Are multiple constraints possible in Sather?

No, but you have multiple inheritance (with ingeniously simple mechanisms to avoid all the hassle of it) so you can just pull two interfaces together to a combined one.

Sather provide sub and super typing operator IIRC, but it can be used to redefine the inheritance hierarchy of two different set of classes? E.g. in library A there's a method that requires something of type NumericComparable that is both Numeric and Comparable. In library B exists class C that inherits from Numeric and Comparable, but not from NumericComparable. The user of these two libraries may say that C inherits from NumericComparable too?

No, but through post-hoc supertyping, he can define MyNumericComparable as a subtype of Numeric and Comparable and a Supertype of C. Anyhow, at that point, the whole class system gets too different from D to be discussed on this list fruitfully. Ciao, Nobbi
Jan 18 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Norbert Nemec" <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> wrote
in message news:b0bej0$18bu$1 digitaldaemon.com...
 Dream on! Ingenious ideas have always suddenly sprung up from somewhere,

 the hardest part always was to recognize them as such. There are probably
 tons of ingenious ideas hidden in the discussions of this newsgroup,

You're right about that, and I've adopted more than a few into D.
 but in
 the end it will be the responsibility of Walter to pick out the good ones.

My worry is that some adverse combinations of features of D will box it into a corner.
 And that will always need some geniality on its own... :-)

Saying no to someone's proposed feature they expended a lot of thought and effort into presenting is really the hardest part of my task. I know how they feel, as not one of my proposed changes ever was adopted by the C++ standards people <g>. (And hence, the genesis of D.)
Feb 15 2003
prev sibling parent reply Marcelo Fontenele S Santos <msantos pobox.com> writes:
Daniel Yokomiso wrote:
 
     The way I see it, a template is always correct. The complete set of
 requirements that a type parameter must meet is in all the possible usages
 inside the template (all execution paths). So if the template requires your
 type to provide + & [] .connectToSQL() operations, it's your problem meeting
 this. At least until we can add operation interfaces. In current mechanisms
 the template determine a structural typing constraint a la OCaml methods on
 their parameters.
 

Hi, In C++ templates there are concepts like iterator, forward_iterator, allocator, etc. They exist, but are not enforced by the language. Maybe in D we could use interfaces to enforce the concepts needed by the templates. And explicitly tell the compiler the concepts/interfaces a certain template type expects. I think it would make error detection much simpler. OT: Just to put my 2 cents, I prefer the proposed template notation using the $ to specify the generic part. -- Marcelo Fontenele S Santos <msantos pobox.com>
Feb 04 2003
parent reply Burton Radons <loth users.sourceforge.net> writes:
Marcelo Fontenele S Santos wrote:
 Daniel Yokomiso wrote:
 
     The way I see it, a template is always correct. The complete set of
 requirements that a type parameter must meet is in all the possible 
 usages
 inside the template (all execution paths). So if the template requires 
 your
 type to provide + & [] .connectToSQL() operations, it's your problem 
 meeting
 this. At least until we can add operation interfaces. In current 
 mechanisms
 the template determine a structural typing constraint a la OCaml 
 methods on
 their parameters.

Hi, In C++ templates there are concepts like iterator, forward_iterator, allocator, etc. They exist, but are not enforced by the language. Maybe in D we could use interfaces to enforce the concepts needed by the templates. And explicitly tell the compiler the concepts/interfaces a certain template type expects. I think it would make error detection much simpler.

Predicate types - or type constraints - are supported by most generic systems that I've seen. One way they could be in D is like this: predicate TComparable ($T) { $T a, b; a < b; } A type is TComparable if it can be inserted in this block statement and pass the semantic phase. In use it would be, say: $T min ($T first, $T [] rest...) predicate TComparable ($T) body { foreach ( ; i in rest; ) { if (i < first) first = i; } return first; } This is more powerful than Eiffel's syntax because you can include multiple arguments to the predicate and fail a set of types because of an incompatible interaction. It could even include type arguments to act as specialisations. So for example: predicate TMatrix4x4 (int $Rows, int $Cols) { assert ($Rows == 4 && $Cols == 4); } struct Matrix ($T, int $Rows, int $Cols) predicate TMatrix4x4 ($Rows, $Cols) body { /* Various SIMD functionality. */ }
Feb 04 2003
parent Marcelo Fontenele S Santos <msantos pobox.com> writes:
Burton Radons wrote:
 Predicate types - or type constraints - are supported by most generic 
 systems that I've seen.  One way they could be in D is like this:
 
    predicate TComparable ($T)
    {
        $T a, b;
 
        a < b;
    }
 
 A type is TComparable if it can be inserted in this block statement and 
 pass the semantic phase.  In use it would be, say:
 
    $T min ($T first, $T [] rest...)
    predicate TComparable ($T)
    body
    {
        foreach ( ; i in rest; )
        {
            if (i < first)
                first = i;
        }
        return first;
    }
 

The problem I see with this approach is that you can add something to the body that is not tested in the predicate. So it would pass the test but could fail to instantiate for a specific type. Before I give my sugestion I must say that I don't know anything about compilers. So anything I say can be impossible or unnecessary. My sugestion is to use template interfaces: interface TComparable($T) // $T is the self type { int cmp( $T rhs ); } And maybe a syntax like: $T min ($T first, $T [] rest...) use($T) TComparable { ... } This means $T must implement that interface and in the body it would only allow the use of $T vars through interface defined calls. $T search( $T first1, $T last1, $U first2, $U last2 ) use($T) TForwardIterator, use($U) TForwardIterator { ... } Extending the above example to be more restrictive we could do: interface TComparable( $T, $U ) { // $T is self type int cmp( $U rhs ); // compare itself with another type } $T search( $T first1, $T last1, $U first2, $U last2 ) use($T) TForwardIterator, use($U) TForwardIterator, use(*$T, *$U) TComparable // TForwardIterator must provide a * op { ... } The problem I see is with built-in types. I don't know how the operators relate to the overloadable methods. Should this work? int i = 0; if ( i.cmp( 0 ) == 0 ) { printf("ok\n"); } It doesn't compile in dli-0.1.2. I also don't know how to check if they implement an interface. For it to work, interfaces should not need to be defined in the class (they could be to detect errors). They would have to be checked during compilation. class X : TComparable { // ok X must implement cmp int cmp( X x ); } class Y { int cmp( Y y ); } TComparable c = (TComparable) Y; // ok Y implements cmp So it would work for built-ins. int i = 0; TComparable c = (TComparable) i; // ok int implements cmp Sugestions? Opinions? -- Marcelo Fontenele S Santos <msantos pobox.com>
Feb 05 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> wrote
in message news:b08u26$2orh$1 digitaldaemon.com...
 Probably, the whole power of the C++ template
 mechanism was never actually planned.

It wasn't. I remember Bjarne's original template paper, and conversations with him about it. The original scheme was not much more than a glorified macro substitution scheme, and few thought it would be hard to implement <g>. There was no hint it would evolve into what it is today.
 Actually, the fact that it hides a
 complete language on its own was even found by accident.

Yes.
 And up to now, I
 guess nobody has really pinned down what the details are that make it so
 powerful. Guess it will take a good portion of genious to extract that

 without carrying over all the drawbacks...

I think the partial specialization is the real source of the power of templates.
Feb 15 2003