D - Serious deficiencies in template mechanism
- Norbert Nemec (68/68) Jan 15 2003 Hi there,
- Norbert Nemec (22/22) Jan 15 2003 I guess, my remark directly collides with the message "C and/or C++ in D...
- Daniel Yokomiso (15/37) Jan 16 2003 Hi,
- Norbert Nemec (15/29) Jan 17 2003 Very true. Al these parts have to play together. As far as I can see it,...
- Daniel Yokomiso (13/42) Jan 17 2003 in
- Norbert Nemec (7/10) Jan 20 2003 You may also take a look at SAC (Single Assignment C) at
- Daniel Yokomiso (8/18) Jan 20 2003 SAC is also very nice too. IMO their array semantics could be extended t...
- Theodore Reed (15/23) Jan 15 2003 On Wed, 15 Jan 2003 11:34:14 +0100
- Norbert Nemec (5/27) Jan 17 2003 OK, but as I understand it, this needs to be called like:
- Walter (14/82) Jan 15 2003 Comments embedded...
- Ilya Minkov (1/5) Jan 15 2003 I'm sorry, i've searched through a bit but was unable to find it.
- Daniel Yokomiso (47/63) Jan 16 2003 [snip]
- Walter (12/56) Jan 18 2003 value
- Norbert Nemec (2/8) Jan 18 2003 Hopefully bits and enums as well?
- Daniel Yokomiso (90/102) Jan 18 2003 define
- Daniel Yokomiso (32/100) Jan 16 2003 Hi,
- Norbert Nemec (28/75) Jan 17 2003 I'm not sure whether that should really be the correct way to say it.
- Daniel Yokomiso (36/111) Jan 17 2003 been
- Norbert Nemec (14/31) Jan 18 2003 No, but you have multiple inheritance (with ingeniously simple mechanism...
- Daniel Yokomiso (40/102) Jan 18 2003 to
- Norbert Nemec (7/30) Jan 18 2003 No, but through post-hoc supertyping, he can define MyNumericComparable ...
- Walter (10/16) Feb 15 2003 and
- Marcelo Fontenele S Santos (12/21) Feb 04 2003 Hi,
- Burton Radons (35/61) Feb 04 2003 Predicate types - or type constraints - are supported by most generic
- Marcelo Fontenele S Santos (61/86) Feb 05 2003 The problem I see with this approach is that you can add something to
- Walter (10/18) Feb 15 2003 It wasn't. I remember Bjarne's original template paper, and conversation...
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
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
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, NobbiHi, 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
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
"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> escreveu na mensagem news:b08ums$2p3a$1 digitaldaemon.com...Daniel Yokomiso wrote:inHi, 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 justthesome 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 ofC++- 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 libraryauthorsthe tools necessary to do their best. Ciao, NobbiWe 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
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
"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> escreveu na mensagem news:b0h0gs$159b$1 digitaldaemon.com...Daniel Yokomiso wrote: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/2003We 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
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
Theodore Reed wrote:On Wed, 15 Jan 2003 11:34:14 +0100 Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> wrote: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.* 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.
Jan 17 2003
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 -- butidentical --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 likedirectvector or matrix manipulations via operators with complete type checking. (Going far beyond the simple possibilities of direct array manipulationsinD.)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.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. -------------------------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 Dmakingit 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 aredesignof 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 donetoreally 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
This is probably going to have to be added to D. Nobody seems to like the alternative mechanism I proposed <g>.I'm sorry, i've searched through a bit but was unable to find it.
Jan 15 2003
In article <b04fq8$8t8$1 digitaldaemon.com>, Walter says...[snip][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 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.------------------------- * Integers as template arguments: template <int N> class Vector { double data[N]; }; making Vector<2> a different type than Vector<3>, allowing stuff likedirectvector or matrix manipulations via operators with complete type checking. (Going far beyond the simple possibilities of direct array manipulationsinD.)This is probably going to have to be added to D. Nobody seems to like the alternative mechanism I proposed <g>.
Jan 16 2003
"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 ofvalueparameters 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 amethodList(U) map(U (*operation)(T)). This is a very good thing to have.I don't understand.proposal allows definition of generic classes with generic methods, andyou haveto instantiate the generic method when you use it, not when youinstantiate thegeneric class. This, together with integer template parameters will allowD tohave 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 thecodeuses 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 aburdenwhen we compare it to the benefits it brings. Best regards, Daniel Yokomiso.
Jan 18 2003
Walter wrote:"Daniel Yokomiso" <Daniel_member pathlink.com> wrote:Hopefully bits and enums as well?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.
Jan 18 2003
"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...defineI'm glad you're considering adding this to the language. Which kind ofvalueparameters 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'tWe 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. 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/2003templates which define templatized methods. E.g. a List(T) class with amethodList(U) map(U (*operation)(T)). This is a very good thing to have.I don't understand.
Jan 18 2003
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, NobbiC++ 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
Daniel Yokomiso wrote:In article <b03d7n$2m9r$1 digitaldaemon.com>, Norbert Nemec says...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?------------------------- 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 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
"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> escreveu na mensagem news:b08u26$2orh$1 digitaldaemon.com...Daniel Yokomiso wrote:beenIn article <b03d7n$2m9r$1 digitaldaemon.com>, Norbert Nemec says...------------------------- The one thing that I dislike most about C++ templates, and which hasthecarried 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,likeapplication programmer may get a huge bunch of error messages lookingseta 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 aparameters: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 typeIttemplate 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.aI 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 oftemplate 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.heC++ template mechanism is very powerful, but almost impossible to get right. Walter writes C++ compiler writes since the beginning of C++, sosomethingknows 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 wantspartbetter, 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 thatwithout carrying over all the drawbacks... Ciao, NobbiMaybe 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
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
"Norbert Nemec" <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> escreveu na mensagem news:b0bej0$18bu$1 digitaldaemon.com...Daniel Yokomiso wrote:toMaybe 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 mechanismsavoid all the hassle of it) so you can just pull two interfaces togethertoa 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?usagesThe way I see it, a template is always correct. The complete set of requirements that a type parameter must meet is in all the possibleprobleminside the template (all execution paths). So if the template requires your type to provide + & [] .connectToSQL() operations, it's yourOr rely on the intelligent and informative error messages from the compiler ;-)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.andMaybe 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, butinthe 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:toMaybe 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 mechanismsavoid all the hassle of it) so you can just pull two interfaces togethertoa 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?usagesThe way I see it, a template is always correct. The complete set of requirements that a type parameter must meet is in all the possibleprobleminside the template (all execution paths). So if the template requires your type to provide + & [] .connectToSQL() operations, it's yourOr rely on the intelligent and informative error messages from the compiler ;-)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.andMaybe 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, butinthe 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
Daniel Yokomiso wrote:"Norbert Nemec" <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>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, NobbiDaniel Yokomiso wrote: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?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.
Jan 18 2003
"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,andthe 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
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
Marcelo Fontenele S Santos wrote:Daniel Yokomiso 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; } 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. */ }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.
Feb 04 2003
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
"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 thatpartwithout carrying over all the drawbacks...I think the partial specialization is the real source of the power of templates.
Feb 15 2003