On Sunday, 15 March 2015 at 10:40:17 UTC, w0rp wrote:
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,
bearophile
It'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.
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.