So I missed the boat on the lengthy Rust traits discussion on the other thread. I confess I didn't have time to read all of it so forgive me if I bring up something that's already been said there.

Since last year, after having written a ton of generic code with compile-time reflection and (although it didn't have a name at the time) design by introspection, I got pretty annoyed at having to debug why my template constraints failed. So I had an idea and it's been waiting for me to write a DIP ever since. I don't think I have time right now to write the DIP properly, but given the recent discussion, here's a sketch. Say I have:

void func(R)(R range) if(isInputRange!R) { ... }

Maybe I didn't even write the function, maybe it's in Phobos. But I'm interested in implementing an input range but this fails to instantiate. I have no idea why. Now, it's usually good practice to include a `static assert(isInputRange!MyType)` somewhere, but if that fails... you have no idea why. Was it `popFront`? `front`? `empty`? Why didn't it compile?

I've resorted to copying the code from the lambda in the customary `is(typeof({...}))` in the template constraint and forcing the compiler to give the message that it's hiding from me. The compiler knows why the static assert failed, but it won't tell me unless I force it to.

This is analogous to dynamic dispatch except, in that case, the compiler will quite gladly tell you if you forgot to implement a virtual function and much more besides. And why can it do that? Because you told it your class implements an interface or inherits from a class with abstract functions / methods.

So... instead of having traits / concepts, what I wanted from D is to be able to do this:

struct MyRange: isInputRange { ... }

or

struct MyRange: static isInputRange { ... } // that way classes could do this too

Then instead of:

foo.d(9): Error: static assert  (isInputRange!(MyRange)) is false

I'd get:

foo.d(9): Error: MyRange does not implement popFront


I'd hoped to paste the result of trying to compile isInputRange in the 2nd example but apparently right now I get the very horrible:

foo.d(17): Error: template std.range.primitives.popFront cannot deduce function from argument types !()(MyRange), candidates are: /usr/include/dlang/dmd/std/range/primitives.d(1992): std.range.primitives.popFront(T)(ref T[] a) if (!isNarrowString!(T[]) && !is(T[] == void[])) /usr/include/dlang/dmd/std/range/primitives.d(2015): std.range.primitives.popFront(C)(ref C[] str) if (isNarrowString!(C[])) foo.d(22): Error: template instance foo.func!(MyRange) error instantiating



At least it mentions `popFront`. Anyway, you understand what I want from this. The only I think I've seen that comes close to achieving this is a massive hack abusing __ctfe in Adam's book.

I've lost count of how many times a template constraint failed because of some stupid thing like @safe functions not being able to call @system ones and it was really hard figuring out why.

I don't want C++ concepts. I just want compiler error messages pointing me in the general direction of why my type fails a template constraint. This is especially bad when there are several overloads with different constraints, I usually have to comment out code until the offending one presents itself.

Atila

Reply via email to