digitalmars.D - Template constraints
- bearophile (10/10) Mar 15 2015 Observe:
Observe: https://github.com/D-Programming-Language/phobos/pull/3054 Is this change the partial proof of another failure of a part of D language design? What's the point of template constraints? Aren't C++ Concepts better? Or to rephrase that in a less trollish way, can D be enhanced to add user-defined error messages to template constraints, and is such enhancement a good idea? Bye, bearophile
Mar 15 2015
On Sunday, 15 March 2015 at 08:29:01 UTC, bearophile wrote:Observe: https://github.com/D-Programming-Language/phobos/pull/3054 Is this change the partial proof of another failure of a part of D language design? What's the point of template constraints? Aren't C++ Concepts better? Or to rephrase that in a less trollish way, can D be enhanced to add user-defined error messages to template constraints, and is such enhancement a good idea? Bye, bearophileIt's funny you mentioned concepts, because I was just watching Bjarne's CppCon 2014 keynote again and I took away two things from it. 1. For the overwhelming majority of things Bjarne wants from C++ mentioned in that keynote, D has done all of them, and better... 2. ...except for concepts. I believe D does the template error message thing a *whole lot* better than C++. That's all because of template constraints, static if, and static assert, and I believe those are down to Andrei's influence. (Though others likely deserve credit for their design, implementation, and maintenance. As always you'll probably have to nod to Kenji who works like crazy.) I've been wondering what we can do to make specifying constraints for something like ranges a little easier to write, with obviously some underlying complexities which will be hard to implement. This doesn't address your concern about error messages for constraints really, but what I've thought of is roughly this. Say you write 'copy' currently. You'll do something like this. void copy(InputRange, OutputRange)(InputRange inputRange, OutputRange) if (isInputRange!InputRange && isOutputRange!OutputRange) { /* Some implementation of copying. */ } Maybe you'll use less verbose names and all kinds of things, but essentially that is what you're after. I've been wondering if it's possible to use compiler magic to make this possible. // These names conflict with our interfaces in std.range, whatever, imagine // some other name place of them if you like. template InputRange(T) { enum InputRange = isInputRange!T; } // The newer syntax makes the above easier... enum OutputRange(T) = isOutputRange!T; // Now this works with magic... void copy()(InputRange inputRange, OutputRange outputRange) { /* Some implementation of copying. */ } If you write this now, the compiler will print an error saying, "Hey, you just attempted to use this template which takes one argument as a type in this paramter list right here." My idea is to take that information and instead of returning an error, just go, "Oh, I'll just add another template parameter onto the end of your template parameter list here, replace the thing which really should be a type here with T from the parameter list, use deduction to insert the type for T and then use it, then use the template you had originally as a test on the type T yielding our boolean expression." I left the extra parens in there for 'copy' as I reckon they'll probably be a requirement anyway, and then you can't make accidental templates. You might have to read what I wrote four times to make sense of it, but that's my crazy idea others can destroy. I'm more of a wild idea guy than a formal specification guy.
Mar 15 2015
On Sunday, 15 March 2015 at 10:40:17 UTC, w0rp wrote:On Sunday, 15 March 2015 at 08:29:01 UTC, bearophile wrote:I am not sure of what you want to do but that looks like "meta-type" like : void copy(InputRange IRage, OutputRange ORange) (IRange src, Orange dest) { /* Some implementation of copying. */ } Hashkell has something like that for a long times (early 90s I think) wich is call type classes. Essentially, it checks that the type implement a certain interface (operators included). You could do the same in c++ with boost (now maybe std)::is_base_of I think.Observe: https://github.com/D-Programming-Language/phobos/pull/3054 Is this change the partial proof of another failure of a part of D language design? What's the point of template constraints? Aren't C++ Concepts better? Or to rephrase that in a less trollish way, can D be enhanced to add user-defined error messages to template constraints, and is such enhancement a good idea? Bye, bearophileIt's funny you mentioned concepts, because I was just watching Bjarne's CppCon 2014 keynote again and I took away two things from it. 1. For the overwhelming majority of things Bjarne wants from C++ mentioned in that keynote, D has done all of them, and better... 2. ...except for concepts. I believe D does the template error message thing a *whole lot* better than C++. That's all because of template constraints, static if, and static assert, and I believe those are down to Andrei's influence. (Though others likely deserve credit for their design, implementation, and maintenance. As always you'll probably have to nod to Kenji who works like crazy.) I've been wondering what we can do to make specifying constraints for something like ranges a little easier to write, with obviously some underlying complexities which will be hard to implement. This doesn't address your concern about error messages for constraints really, but what I've thought of is roughly this. Say you write 'copy' currently. You'll do something like this. void copy(InputRange, OutputRange)(InputRange inputRange, OutputRange) if (isInputRange!InputRange && isOutputRange!OutputRange) { /* Some implementation of copying. */ } Maybe you'll use less verbose names and all kinds of things, but essentially that is what you're after. I've been wondering if it's possible to use compiler magic to make this possible. // These names conflict with our interfaces in std.range, whatever, imagine // some other name place of them if you like. template InputRange(T) { enum InputRange = isInputRange!T; } // The newer syntax makes the above easier... enum OutputRange(T) = isOutputRange!T; // Now this works with magic... void copy()(InputRange inputRange, OutputRange outputRange) { /* Some implementation of copying. */ } If you write this now, the compiler will print an error saying, "Hey, you just attempted to use this template which takes one argument as a type in this paramter list right here." My idea is to take that information and instead of returning an error, just go, "Oh, I'll just add another template parameter onto the end of your template parameter list here, replace the thing which really should be a type here with T from the parameter list, use deduction to insert the type for T and then use it, then use the template you had originally as a test on the type T yielding our boolean expression." I left the extra parens in there for 'copy' as I reckon they'll probably be a requirement anyway, and then you can't make accidental templates. You might have to read what I wrote four times to make sense of it, but that's my crazy idea others can destroy. I'm more of a wild idea guy than a formal specification guy.
Mar 15 2015
Sorry for the mistakes in the above message (and in this one). I didnt gave earlier my personnal opinion on the matter but essentially if I like the syntax of type classes very much, you can do much more with templates constraint and D meta programming abilities...But you still have to fix some kind of pragmatic limit in the compile time introspection I think...
Mar 15 2015