www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Template constraints in D

reply Walter Bright <newshound1 digitalmars.com> writes:
(Also comparing them with C++0x concepts.)

http://www.digitalmars.com/d/2.0/cpp0x.html#concepts

http://www.digitalmars.com/d/2.0/concepts.html

Essentially, I think we cover the necessary ground with an order of 
magnitude simpler system.
Jun 20 2008
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 
 (Also comparing them with C++0x concepts.)
 
 http://www.digitalmars.com/d/2.0/cpp0x.html#concepts
 
 http://www.digitalmars.com/d/2.0/concepts.html
 
 Essentially, I think we cover the necessary ground with an order of 
 magnitude simpler system.

Maybe you should provide an example somewhere of how to translate this basic C++0x example into D: ---- auto concept LessThanComparable<typename T> { bool operator<(T, T); }; template<LessThanComparable T> const T& min(const T& x, const T& y) { return x < y? x : y; } ---- --bb
Jun 21 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 Maybe you should provide an example somewhere of how to translate this 
 basic C++0x example into D:
 
 ----
 auto concept LessThanComparable<typename T> {
     bool operator<(T, T);
 };
 
 template<LessThanComparable T>
 const T& min(const T& x, const T& y) {
     return x < y? x : y;
 }
 ----

See the isAddable example.
Jun 21 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 Maybe you should provide an example somewhere of how to translate this 
 basic C++0x example into D:

 ----
 auto concept LessThanComparable<typename T> {
     bool operator<(T, T);
 };

 template<LessThanComparable T>
 const T& min(const T& x, const T& y) {
     return x < y? x : y;
 }
 ----

See the isAddable example.

A more natural way to declare required functions would be nice. First of all, about the isAddable example, can't you just use T.init instead of writing an anonymous delegate? Like __traits(compiles, T.init + T.init) Anyway, for a less trivial example I think that becomes pretty cumbersome. E.g.: concept Stack<typename X> { typename value_type; void push(X&, const value_type&); void pop(X&); value_type top(const X&); bool empty(const X&); }; is going to translate to something like this?: template Stack(T) { const Stack = is(T.value_type) && __traits(compiles, (T t, T.value_type v) { push(t, v); }) && __traits(compiles, (T t) { pop(t); }) && __traits(compiles, (T t) { top(t); }) && is(typeof(top(T.init))==T.value_type) && __traits(compiles, (T t) { empty(t) }) && is(typeof(empty(T.init))==bool); } I hope you can work out a way to give this a more natural syntax, like Concepts will have in C++0x. ---- An unrelated comment is that I don't think it is relevant or respectful to compare the lengths of the specs. The spec for Concepts that you link to includes many many more in depth examples than the D spec does. It's an apples vs oranges comparison. So 5 pages vs 49 pages really doesn't have much meaning at all. --bb
Jun 21 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 A more natural way to declare required functions would be nice.
 
 First of all, about the isAddable example, can't you just use T.init 
 instead of writing an anonymous delegate?  Like
    __traits(compiles, T.init + T.init)

I think you're right.
 Anyway, for a less trivial example I think that becomes pretty 
 cumbersome.  E.g.:
 
 concept Stack<typename X> {
   typename value_type;
   void push(X&, const value_type&);
   void pop(X&);
   value_type top(const X&);
   bool empty(const X&);
 };
 
 is going to translate to something like this?:
 
 template Stack(T)
 {
     const Stack =
         is(T.value_type) &&
         __traits(compiles, (T t, T.value_type v) { push(t, v); }) &&
         __traits(compiles, (T t) { pop(t); }) &&
         __traits(compiles, (T t) { top(t); }) &&
         is(typeof(top(T.init))==T.value_type) &&
         __traits(compiles, (T t) { empty(t) }) &&
         is(typeof(empty(T.init))==bool);
 }
 
 I hope you can work out a way to give this a more natural syntax, like 
 Concepts will have in C++0x.

You're the first I've heard say that Concepts have a natural syntax! But let me try: template Stack(T) { const Stack = __traits(compiles, (T t) { T.value_type v = top(t); push(t, v); pop(t); if (empty(t)){} }); } The idea is that the desired operations are expressed as operations, rather than as function signatures.
 An unrelated comment is that I don't think it is relevant or respectful 
 to compare the lengths of the specs.  The spec for Concepts that you 
 link to includes many many more in depth examples than the D spec does. 
  It's an apples vs oranges comparison.  So 5 pages vs 49 pages really 
 doesn't have much meaning at all.

I wished to make the point that D constraints build on what one already knows - how to write a D expression. Concepts, on the other hand, have a major new syntax and semantic thing that must be learned. Perhaps I expressed the point badly, do you have a suggestion?
Jun 21 2008
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 A more natural way to declare required functions would be nice.

 First of all, about the isAddable example, can't you just use T.init 
 instead of writing an anonymous delegate?  Like
    __traits(compiles, T.init + T.init)

I think you're right.
 Anyway, for a less trivial example I think that becomes pretty 
 cumbersome.  E.g.:

 concept Stack<typename X> {
   typename value_type;
   void push(X&, const value_type&);
   void pop(X&);
   value_type top(const X&);
   bool empty(const X&);
 };

 is going to translate to something like this?:

 template Stack(T)
 {
     const Stack =
         is(T.value_type) &&
         __traits(compiles, (T t, T.value_type v) { push(t, v); }) &&
         __traits(compiles, (T t) { pop(t); }) &&
         __traits(compiles, (T t) { top(t); }) &&
         is(typeof(top(T.init))==T.value_type) &&
         __traits(compiles, (T t) { empty(t) }) &&
         is(typeof(empty(T.init))==bool);
 }

 I hope you can work out a way to give this a more natural syntax, like 
 Concepts will have in C++0x.

You're the first I've heard say that Concepts have a natural syntax!

Well, I didn't go very far into that spec document you link to, but I think the Stack example above (which I took from there) is really straightforward. It looks just like a kind of interface declaration. Since concepts are trying to express compile-time interfaces, that makes plenty of sense.
 But let me try:
 
 template Stack(T)
 {
     const Stack =
         __traits(compiles,
         (T t)
         {    T.value_type v = top(t);
              push(t, v);
              pop(t);
              if (empty(t)){}
         });
 }
 
 The idea is that the desired operations are expressed as operations, 
 rather than as function signatures.

I do like the idea -- show the actual code you want to work, not something one-step removed like "has an opAdd member". Still, anything containing __traits looks like an afterthought. Also, I'm not sure how it's going to work in C++, but isn't the compiler going to have a hard time reporting errors in that kind of thing? Failure to instantiate could be because of a very minor typo in the big list of constraints. I'm not sure how C++ will deal with that, but I think it's another place where concept maps help. They introduce a little redundancy. They give you a place to say "I think type X satisfies concept Y, and here's how". That gives the compiler a place to say, "No you're wrong, type X does not satisfy concept Y because Foo isn't actually a method of X". It seems like it should be possible to generate very readable error messages from that.
 An unrelated comment is that I don't think it is relevant or 
 respectful to compare the lengths of the specs.  The spec for Concepts 
 that you link to includes many many more in depth examples than the D 
 spec does.  It's an apples vs oranges comparison.  So 5 pages vs 49 
 pages really doesn't have much meaning at all.

I wished to make the point that D constraints build on what one already knows - how to write a D expression. Concepts, on the other hand, have a major new syntax and semantic thing that must be learned. Perhaps I expressed the point badly, do you have a suggestion?

I think the number of new keywords expresses that well enough. You could also add something like "new syntactic constructs: 1 vs [however many concepts add]". I think you can pretty much count up the gray boxes in the Concepts spec to get that number. Or maybe call it "new productions added to grammar". --bb
Jun 21 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 Still, anything 
 containing __traits looks like an afterthought.

A bit.
 Also, I'm not sure how it's going to work in C++, but isn't the compiler 
 going to have a hard time reporting errors in that kind of thing? 
 Failure to instantiate could be because of a very minor typo in the big 
 list of constraints.

True, you won't have an indication which failed. But you won't in C++, either, because the overload just won't be matched.
 I'm not sure how C++ will deal with that, but I think it's another place 
 where concept maps help.  They introduce a little redundancy.  They give 
 you a place to say "I think type X satisfies concept Y, and here's how". 
  That gives the compiler a place to say, "No you're wrong, type X does 
 not satisfy concept Y because Foo isn't actually a method of X".  It 
 seems like it should be possible to generate very readable error 
 messages from that.

Because you can overload based on concepts, I don't see how the compiler can give an error message saying it failed to match part of a concept.
Jun 22 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 Still, anything containing __traits looks like an afterthought.

A bit.
 Also, I'm not sure how it's going to work in C++, but isn't the 
 compiler going to have a hard time reporting errors in that kind of 
 thing? Failure to instantiate could be because of a very minor typo in 
 the big list of constraints.

True, you won't have an indication which failed. But you won't in C++, either, because the overload just won't be matched.

Only true for C++ 'auto' concepts. """ The auto specifier means that any type which has a suitable operator< will be considered LessThanComparable; if omitted, the user will have to explicitly state that her types meet the requirements of the concept using a concept map """ As I said after that, I'm thinking more about the non-auto case, where you specify a concept_map.
 
 I'm not sure how C++ will deal with that, but I think it's another 
 place where concept maps help.  They introduce a little redundancy.  
 They give you a place to say "I think type X satisfies concept Y, and 
 here's how".  That gives the compiler a place to say, "No you're 
 wrong, type X does not satisfy concept Y because Foo isn't actually a 
 method of X".  It seems like it should be possible to generate very 
 readable error messages from that.

Because you can overload based on concepts, I don't see how the compiler can give an error message saying it failed to match part of a concept.

No, I mean when you have a concept_map the error can be generated at the point the concept_map is declared. Telling the user the concept he thought he was implementing isn't being implemented. I think in D you could do some variation of static assert(is(typeof(conceptStack!(Foo))), "Foo doesn't implement Stack concept"); (using DeeGirl's template: void stackConcept(T)() { T t; T.value_type v = top(t); push(t, v); pop(t); if (empty(t)){} } ) BUT the static assert will just tell you Foo does not qualify as a Stack, it won't tell you why. Whereas the C++0x compiler with a concept map could tell you specifically what part of the concept is lacking. But of course the main benefit of concept maps is that when I want to plug Vinces's Vector class into Larry's LinearSolver class all I have to do is specify how Vince's Vector satisfies Larry's VectorConcept. And it doesn't matter if Vince overloaded opMul to mean dot product, but Larry expects a member named "dot". Maybe if you haven't yet you could talk it over with Andrei. My experience is that discussing things with you here on the NG is not all that productive because you only ever respond with one or two sentences, so that's all I'm going to say about this. --bb
Jun 22 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 But of course the main benefit of concept maps is that when I want to 
 plug Vinces's Vector class into Larry's LinearSolver class all I have to 
 do is specify how Vince's Vector satisfies Larry's VectorConcept.  And 
 it doesn't matter if Vince overloaded opMul to mean dot product, but 
 Larry expects a member named "dot".

You can do that with a proxy object.
 Maybe if you haven't yet you could talk it over with Andrei.  My 
 experience is that discussing things with you here on the NG is not all 
 that productive because you only ever respond with one or two sentences, 
 so that's all I'm going to say about this.

I find it difficult to have productive discussions via email (even with Andrei). The upcoming D conference, however, will give everyone a chance for face-to-face.
Jun 22 2008
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:g3mkb9$sel$2 digitalmars.com...

 I find it difficult to have productive discussions via email (even with 
 Andrei). The upcoming D conference, however, will give everyone a chance 
 for face-to-face.

Then use a newsgroup client ;)
Jun 22 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Jarrett Billingsley wrote:
 "Walter Bright" <newshound1 digitalmars.com> wrote in message 
 news:g3mkb9$sel$2 digitalmars.com...
 
 I find it difficult to have productive discussions via email (even with 
 Andrei). The upcoming D conference, however, will give everyone a chance 
 for face-to-face.

Then use a newsgroup client ;)

That isn't the answer. What's lacking is the face-to-face. There's just nothing like sitting around a table, with coffee and a notebook, and sketching things out.
Jun 22 2008
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Walter Bright" <newshound1 digitalmars.com> wrote in message 
news:g3n0ob$1dni$1 digitalmars.com...

 That isn't the answer. What's lacking is the face-to-face. There's just 
 nothing like sitting around a table, with coffee and a notebook, and 
 sketching things out.

My reply was meant to be tongue-in-cheek ;) Still, conversing face-to-face, while better, isn't really much of an option when 99.999% of the community doesn't live in Seattle. Sorry, you really do need to work on your textual communication skills. They're not the same, but they're still important.
Jun 22 2008
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 But of course the main benefit of concept maps is that when I want to 
 plug Vinces's Vector class into Larry's LinearSolver class all I have 
 to do is specify how Vince's Vector satisfies Larry's VectorConcept.  
 And it doesn't matter if Vince overloaded opMul to mean dot product, 
 but Larry expects a member named "dot".

You can do that with a proxy object.

A) How exactly? If you're going to claim it's equivalent, I think the burden is on you to show an example of it. B) Whatever you have in mind, my hunch is that it is going to be significantly more cumbersome. For example in my code I like using Vince's Vector. I like his API. But if I go with proxy objects then I think that means either I have to use the proxy object (with Larry's API) instead of Vince's Vector directly, or else every time I call Larry's code I have to wrap my Vince Vector in a Larry VectorConcept proxy wrapper. Either way it's not ideal, and more cumbersome than just writing down the mapping once in one central place.
 Maybe if you haven't yet you could talk it over with Andrei.  My 
 experience is that discussing things with you here on the NG is not 
 all that productive because you only ever respond with one or two 
 sentences, so that's all I'm going to say about this.

I find it difficult to have productive discussions via email (even with Andrei). The upcoming D conference, however, will give everyone a chance for face-to-face.

Everyone who can be there at least. Anyway, I think you need to find someone who understands the ins and outs of C++0x concepts and discuss with them face-to-face whether your plan for D covers all the bases sufficiently or not. --bb
Jun 22 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 You can do that with a proxy object.

A) How exactly? If you're going to claim it's equivalent, I think the burden is on you to show an example of it.

The opDot feature allows one to wrap a type, override what you need to and forward the rest to the wrapped object.
 B) Whatever you have in mind, my hunch is that it is going to be 
 significantly more cumbersome.  For example in my code I like using 
 Vince's Vector.  I like his API.  But if I go with proxy objects then I 
 think that means either I have to use the proxy object (with Larry's 
 API) instead of Vince's Vector directly, or else every time I call 
 Larry's code I have to wrap my Vince Vector in a Larry VectorConcept 
 proxy wrapper.  Either way it's not ideal, and more cumbersome than just 
 writing down the mapping once in one central place.

Implicit casting casts from, and constructors cast to. That should handle it.
 Anyway, I think you need to find 
 someone who understands the ins and outs of C++0x concepts and discuss 
 with them face-to-face whether your plan for D covers all the bases 
 sufficiently or not.

It doesn't need to cover all the bases. It only has to cover the relevant useful ones. I should also point out that there are areas where D's constraint system is far more powerful (try doing isPrime() in C++). One thing to keep in mind is C++ concepts are very complicated. There's a lot of grammar, a lot of explanation, a lot of special cases to understand. None of it has proven useful in production code (that will take years). You have to stack up that high implementation cost and high learning cost for programmers up against the utility of it - just what doors does it really open? Is it a paradigm changing feature? I don't see it. On the other hand, constraints are trivial to implement, simple to understand (they build on what you already know - expressions), and arguably get the meat of what concepts do and extend it.
Jun 22 2008
parent reply downs <default_357-line yahoo.de> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 You can do that with a proxy object.

A) How exactly? If you're going to claim it's equivalent, I think the burden is on you to show an example of it.

The opDot feature allows one to wrap a type, override what you need to and forward the rest to the wrapped object.

Interesting. Even operators?
Jun 23 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
downs wrote:
 Walter Bright wrote:
 The opDot feature allows one to wrap a type, override what you need to
 and forward the rest to the wrapped object.

Interesting. Even operators?

Toto too!
Jun 23 2008
parent downs <default_357-line yahoo.de> writes:
Walter Bright wrote:
 downs wrote:
 Walter Bright wrote:
 The opDot feature allows one to wrap a type, override what you need to
 and forward the rest to the wrapped object.

Interesting. Even operators?

Toto too!

I'm now officially in love with that feature.
Jun 23 2008
prev sibling parent reply downs <default_357-line yahoo.de> writes:
Walter Bright wrote:
 I find it difficult to have productive discussions via email (even with
 Andrei). The upcoming D conference, however, will give everyone a chance
 for face-to-face.

Except, of course, those who can't afford plane tickets. Just my two eurocents.
Jun 23 2008
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"downs" <default_357-line yahoo.de> wrote in message 
news:g3nvt3$98d$3 digitalmars.com...
 Walter Bright wrote:
 I find it difficult to have productive discussions via email (even with
 Andrei). The upcoming D conference, however, will give everyone a chance
 for face-to-face.

Except, of course, those who can't afford plane tickets. Just my two eurocents.

And my two American cents, since flights from the east coast to the west are still not cheap by any means..
Jun 23 2008
prev sibling parent Leandro Lucarella <llucax gmail.com> writes:
downs, el 23 de junio a las 13:03 me escribiste:
 Walter Bright wrote:
 I find it difficult to have productive discussions via email (even with
 Andrei). The upcoming D conference, however, will give everyone a chance
 for face-to-face.

Except, of course, those who can't afford plane tickets. Just my two eurocents.

Don't mention it, it's worse for people that just have argentinian pesos cents =/ -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Si ella es la flor, yo soy la espina Si ella es quien florece, yo quien se marchita Y estamos en eclipse total, y estamos en eclipse total Completamente cruzados, completamente cruzados
Jun 23 2008
prev sibling next sibling parent reply Dee Girl <deegirl noreply.com> writes:
Walter Bright Wrote:

 You're the first I've heard say that Concepts have a natural syntax! But 
 let me try:
 
 template Stack(T)
 {
      const Stack =
          __traits(compiles,
 	    (T t)
 	    {	T.value_type v = top(t);
 		push(t, v);
 		pop(t);
 		if (empty(t)){}
 	    });
 }
 
 The idea is that the desired operations are expressed as operations, 
 rather than as function signatures.

I think is much easier another way. void stackConcept(T)() { T t; T.value_type v = top(t); push(t, v); pop(t); if (empty(t)){} } You simply call is(typeof(stackConcept!(T))) after. It is Very easy.
 An unrelated comment is that I don't think it is relevant or respectful 
 to compare the lengths of the specs.  The spec for Concepts that you 
 link to includes many many more in depth examples than the D spec does. 
  It's an apples vs oranges comparison.  So 5 pages vs 49 pages really 
 doesn't have much meaning at all.

I wished to make the point that D constraints build on what one already knows - how to write a D expression. Concepts, on the other hand, have a major new syntax and semantic thing that must be learned. Perhaps I expressed the point badly, do you have a suggestion?

I hope this is not offensive. I said one that you focus on comparing D with C++ to much. And again you do the same with concepts. Comparison by any body else that you is ok. But if you do comparison is terrible. Makes you look second in run trying to reach first. You are not loser and do not want to look like loser. I study kyokushin karate 9 year. I was not good ^_^ but it was good for me. Sensei said many times best karate ka not compete with others. He compete with himself. Best fighter wants to do his best not only better than others. I understood him after years. I hope I express myself ok. One thing is also you implemented functionality in C++ concepts. Implementation is clever. But you do not bring original thing. You do what the C++ documentation does. Nothing else. It is not creative and not original. D is not C++ monkey. Stop looking at C++, do what you know is good; and you will be happy. Sorry, Dee Girl
Jun 21 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Dee Girl wrote:
 I hope this is not offensive. I said one that you focus on comparing
 D with C++ to much. And again you do the same with concepts.
 Comparison by any body else that you is ok. But if you do comparison
 is terrible. Makes you look second in run trying to reach first. You
 are not loser and do not want to look like loser. I study kyokushin
 karate 9 year. I was not good ^_^ but it was good for me. Sensei said
 many times best karate ka not compete with others. He compete with
 himself. Best fighter wants to do his best not only better than
 others. I understood him after years. I hope I express myself ok.

I understand your point, but I've often run into the sentiment "D looks great, but with C++0x coming I don't need D." So, some sort of comparison with C++0x is warranted. I do hear you, though, which is why the article doesn't focus on C++, and the comparison is off on a separate page.
 One thing is also you implemented functionality in C++ concepts.
 Implementation is clever. But you do not bring original thing. You do
 what the C++ documentation does. Nothing else. It is not creative and
 not original. D is not C++ monkey. Stop looking at C++, do what you
 know is good; and you will be happy. Sorry, Dee Girl

You cannot do the isPrime() thing with Concepts.
Jun 22 2008
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:

 I wished to make the point that D constraints build on what one already 
 knows - how to write a D expression. Concepts, on the other hand, have a 
 major new syntax and semantic thing that must be learned. Perhaps I 
 expressed the point badly, do you have a suggestion?

The new comparison you put in there is definitely a change for the better. --bb
Jun 23 2008
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 http://www.digitalmars.com/d/2.0/concepts.html

They look nice (but I may use a bigger list of examples to understand how they can be used). What can they do that can't be done with the things already present? bool isprime(int n) { ... } template Foo(int N) { static assert (isprime(N), "error"); ... } template Foo(int N) { static if (N & 1) { // A code } else { // B code } Foo!(3) // instantiates Foo with A code Foo!(64) // instantiates Foo with B code Bye, bearophile
Jun 21 2008
next sibling parent janderson <askme me.com> writes:
bearophile wrote:
 Walter Bright:
 http://www.digitalmars.com/d/2.0/concepts.html

They look nice (but I may use a bigger list of examples to understand how they can be used). What can they do that can't be done with the things already present? bool isprime(int n) { ... } template Foo(int N) { static assert (isprime(N), "error"); ... } template Foo(int N) { static if (N & 1) { // A code } else { // B code } Foo!(3) // instantiates Foo with A code Foo!(64) // instantiates Foo with B code Bye, bearophile

For one thing they get away from the big-long-if-statements. That means you can extend a template in a different place, so the code is less brittle. -Joel
Jun 21 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 They look nice (but I may use a bigger list of examples to understand
 how they can be used). What can they do that can't be done with the
 things already present?
 
 bool isprime(int n) { ... } template Foo(int N) { static assert
 (isprime(N), "error"); ... }
 
 
 template Foo(int N) { static if (N & 1) { // A code } else { // B
 code } Foo!(3)    // instantiates Foo with A code Foo!(64)   //
 instantiates Foo with B code

Very good question. The answer is that the user can add overloads that handle more cases without having to edit the original (which may be in a module that is not editable for various reasons).
Jun 21 2008
parent reply Dee Girl <deegirl noreply.com> writes:
Walter Bright Wrote:

 bearophile wrote:
 They look nice (but I may use a bigger list of examples to understand
 how they can be used). What can they do that can't be done with the
 things already present?
 
 bool isprime(int n) { ... } template Foo(int N) { static assert
 (isprime(N), "error"); ... }
 
 
 template Foo(int N) { static if (N & 1) { // A code } else { // B
 code } Foo!(3)    // instantiates Foo with A code Foo!(64)   //
 instantiates Foo with B code

Very good question. The answer is that the user can add overloads that handle more cases without having to edit the original (which may be in a module that is not editable for various reasons).

Good example is a hashtable. If the bucket size is prime then use a strategy. If is a power of two use another strategy. Otherwise use third strategy. Thanks, Dee Girl
Jun 21 2008
parent janderson <askme me.com> writes:
Dee Girl wrote:
 Walter Bright Wrote:
 
 bearophile wrote:
 They look nice (but I may use a bigger list of examples to understand
 how they can be used). What can they do that can't be done with the
 things already present?

 bool isprime(int n) { ... } template Foo(int N) { static assert
 (isprime(N), "error"); ... }


 template Foo(int N) { static if (N & 1) { // A code } else { // B
 code } Foo!(3)    // instantiates Foo with A code Foo!(64)   //
 instantiates Foo with B code

handle more cases without having to edit the original (which may be in a module that is not editable for various reasons).

Good example is a hashtable. If the bucket size is prime then use a strategy. If is a power of two use another strategy. Otherwise use third strategy. Thanks, Dee Girl

I agree, that's a good example. -Joel
Jun 21 2008
prev sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 Walter Bright:
 http://www.digitalmars.com/d/2.0/concepts.html


Nothing. But it's a very convenient syntactic sugar on top of existing techniques, such as: http://www.digitalmars.com/d/archives/digitalmars/D/Stroustrup_s_talk_on_C_0x_57104.html#N5737 9 Walter had even asked me to write an article about this, but I never followed through :p I will say that the __traits(compiles, blah) trick is totally awesome. I was trying to do this in D 1.0 the other day and couldn't find a way to make it work. Figures it would require D 2.0. *sigh* Sean
Jun 21 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Sean Kelly wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 Walter Bright:
 http://www.digitalmars.com/d/2.0/concepts.html


Nothing. But it's a very convenient syntactic sugar on top of existing techniques, such as: http://www.digitalmars.com/d/archives/digitalmars/D/Stroustrup_s_talk_on_C_0x_57104.html#N5737 9 Walter had even asked me to write an article about this, but I never followed through :p I will say that the __traits(compiles, blah) trick is totally awesome. I was trying to do this in D 1.0 the other day and couldn't find a way to make it work. Figures it would require D 2.0. *sigh*

DeeGirl's trick works in D 1.x doesn't it? I.e. a template function + is(typeof(thatTemplateFunction!(T))) --bb
Jun 21 2008
parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Bill Baxter (dnewsgroup billbaxter.com)'s article
 Sean Kelly wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 Walter Bright:
 http://www.digitalmars.com/d/2.0/concepts.html




 can they do that can't be done with the things already present?

 Nothing.  But it's a very convenient syntactic sugar on top of existing
 techniques, such as:


 9

 Walter had even asked me to write an article about this, but I never
 followed through :p

 I will say that the __traits(compiles, blah) trick is totally awesome.  I
 was trying to do this in D 1.0 the other day and couldn't find a way to
 make it work.  Figures it would require D 2.0.  *sigh*

I.e. a template function + is(typeof(thatTemplateFunction!(T)))

Not as far as I know. This is the first thing I tried, and it gave me a compile error when the function couldn't be instantiated. Sean
Jun 22 2008
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Sean Kelly wrote:
 == Quote from Bill Baxter (dnewsgroup billbaxter.com)'s article
 Sean Kelly wrote:
 == Quote from bearophile (bearophileHUGS lycos.com)'s article
 Walter Bright:
 http://www.digitalmars.com/d/2.0/concepts.html




 can they do that can't be done with the things already present?

 Nothing.  But it's a very convenient syntactic sugar on top of existing
 techniques, such as:


 9

 Walter had even asked me to write an article about this, but I never
 followed through :p

 I will say that the __traits(compiles, blah) trick is totally awesome.  I
 was trying to do this in D 1.0 the other day and couldn't find a way to
 make it work.  Figures it would require D 2.0.  *sigh*

I.e. a template function + is(typeof(thatTemplateFunction!(T)))

Not as far as I know. This is the first thing I tried, and it gave me a compile error when the function couldn't be instantiated.

Ok, so I guess the contents of thatTemplateFunction!(T) have to go in-line. Which makes it a bit more of a pain. But I think you can still achieve the same effect. --bb
Jun 22 2008
prev sibling next sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Walter Bright wrote:
 
 (Also comparing them with C++0x concepts.)
 
 http://www.digitalmars.com/d/2.0/cpp0x.html#concepts
 
 http://www.digitalmars.com/d/2.0/concepts.html
 
 Essentially, I think we cover the necessary ground with an order of 
 magnitude simpler system.

Very much so, brilliant! But what about concept maps, the suggestion is to use proxy objects but won't that be very cumbersome? Aren't concept maps important enough? btw. I think it does more than cover necessary ground, with CTFE constraints are more powerful, though that may have limited use.
Jun 21 2008
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Lutger wrote:
 Very much so, brilliant! But what about concept maps, the suggestion is 
 to use proxy objects but won't that be very cumbersome? Aren't concept 
 maps important enough?

I think I understand concept maps, but I don't understand what the compelling use case for their existence is.
Jun 21 2008
parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Walter Bright wrote:

 Lutger wrote:
 Very much so, brilliant! But what about concept maps, the suggestion is
 to use proxy objects but won't that be very cumbersome? Aren't concept
 maps important enough?

I think I understand concept maps, but I don't understand what the compelling use case for their existence is.

In C++ or possibly in D? In this talk - probably posted before - Douglas Gregor also talks about the uses for concept maps, about ten minutes from 36.00 or so: http://www.youtube.com/watch?v=Ot4WdHAGSGo From that talk, as far as I could understand, I think these were the most important aspects: - concept maps are needed to implement the C++ equivalent of D's opApply operator. - they replace the existing ways to define new iterators - map the interface of built-in types to concepts - concept maps make it possible to define partial ordering rules between existing types that you cannot alter. This is not relevant in D right? In general, because concept maps can be used with existing types, they allow for backwards compatibility and increased functionality of existing code. Template constraints make it possible (or much easier) to extend existing templates via overloading, concept maps complete this extensibility in the case both the type and the template exist and are compatible by concept but not syntax, D. Gregor calls this 'syntax remapping'. Whether this is compelling *for D* I don't know.
Jun 22 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Lutger wrote:
 Whether this is compelling *for D* I don't know.

My general approach is unless compelling use cases can be found for D, it isn't worth implementing (because there are already many ideas with compelling use cases). I think the jury will be out for 3 or 4 years for C++ concept maps as to whether the identified use cases are compelling or not.
Jun 22 2008
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
For me, this is the big difference between them:

Semantic analysis of template bodies:
  - D: Lazy (done at instantiation time)
  - C++0x: Eager (done at definition time)

I want to get errors in the template itself, not just know that I've 
done something wrong in my template when some user discovers a bug in 
it. This will also enable IDE support for templates.

Walter Bright a écrit :
 
 (Also comparing them with C++0x concepts.)
 
 http://www.digitalmars.com/d/2.0/cpp0x.html#concepts
 
 http://www.digitalmars.com/d/2.0/concepts.html
 
 Essentially, I think we cover the necessary ground with an order of 
 magnitude simpler system.

Jun 21 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Ary Borenszweig wrote:
 For me, this is the big difference between them:
 
 Semantic analysis of template bodies:
  - D: Lazy (done at instantiation time)
  - C++0x: Eager (done at definition time)
 
 I want to get errors in the template itself, not just know that I've 
 done something wrong in my template when some user discovers a bug in 
 it.

I discussed this with Douglas Gregor, the primary inventor of concepts. It boiled down to, how likely is it that one would ship a template that had never been instantiated, and is that a big enough feature that it needs language support?
 This will also enable IDE support for templates.

I don't see how that is required for IDE support.
Jun 21 2008
prev sibling parent janderson <askme me.com> writes:
Walter Bright wrote:
 (Also comparing them with C++0x concepts.)

 http://www.digitalmars.com/d/2.0/cpp0x.html#concepts

 http://www.digitalmars.com/d/2.0/concepts.html

 Essentially, I think we cover the necessary ground with an order of 

As I understand it, one thing C++0x concepts will be able to do is resolve collisions/overloading in a reasonable way. Can someone can inherit from say isAddable and then write a specialized template for that? Furthermore is there a way to specialize something like: template Foo(T, int N) if (isAddable!(T) && isprime(N)) Once someone has already written that in another lib and you want to add something like: template Foo(T, int N) if (isAddable!(T) && isprime(N) && isLessThen(N, 100)) Can the compiler figure out which to use? Maybe it could in this case, but in more complex example what would it choose? One way that would be possible is to write a new template with a different name that calls Foo. However that's not ideal because then you can't optimize (for instance) places where Foo is already in use. -Joel
Jun 21 2008