www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ideas how to improve template constraint errors

reply Martin Nowak <code dawg.eu> writes:
I'm sitting here trying to figure out why I can't combine join 
pathSplitter components with pathSeparator.

import std.range, std.path;

void bug()
{
     auto comps = pathSplitter("foo/bar");
     auto path = join(comps, pathSeparator);
}

This is the error message:

path.d(6): Error: template std.array.join does not match any function 
template declaration. Candidates are:
DPL/dmd/src/../../phobos/std/array.d(1559):        std.array.join(RoR, 
R)(RoR ror, R sep) if (isInputRange!RoR && 
isInputRange!(ElementType!RoR) && isInputRange!R && 
is(Unqual!(ElementType!(ElementType!RoR)) == Unqual!(ElementType!R)))
DPL/dmd/src/../../phobos/std/array.d(1606): 
std.array.join(RoR)(RoR ror) if (isInputRange!RoR && 
isInputRange!(ElementType!RoR))
path.d(6): Error: template std.array.join(RoR, R)(RoR ror, R sep) if 
(isInputRange!RoR && isInputRange!(ElementType!RoR) && isInputRange!R && 
is(Unqual!(ElementType!(ElementType!RoR)) == Unqual!(ElementType!R))) 
cannot deduce template function from argument types !()(PathSplitter, 
string)

This is what I currently have to do to figure out what is going on.

     // declare types of arguments
     alias RoR = typeof(comps);
     alias R = typeof(pathSeparator);
     // static assert each constraint
     static assert(isInputRange!RoR);
     // Bingo!
     static assert(isInputRange!(ElementType!RoR));
     // path.d(9): Error: static assert  (isInputRange!(const(char[]))) 
is false
     static assert(isInputRange!R);
     static assert(is(Unqual!(ElementType!(ElementType!RoR)) == 
Unqual!(ElementType!R)));

A useful error message should be something along this line.

path.d(6): Error: Can't call template function 'join' because the 
element type of 'comps' is not an input range.

path.d(6): Error: Can't call template function 'join' because the 
following constraint failed.
     isInputRange!(ElementType!RoR), RoR == const(char[]) deduced from 
argument 'comps'.
Dec 05 2013
next sibling parent reply Martin Nowak <code dawg.eu> writes:
Ah well, this was a question for ideas.
I don't really know to get there.
Dec 05 2013
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 5 December 2013 at 13:55:30 UTC, Martin Nowak wrote:
 Ah well, this was a question for ideas.
 I don't really know to get there.
IMO, one of the initial problems is "argument type validation" vs "overload resolution". I've talked about this some before: http://forum.dlang.org/thread/znlqobvvdywdskhiriwx forum.dlang.org It's the kind of thing that I think makes some of our constraints too complicated. -------- This would not have helped you in this situation. While a backend solution would be nice, I also think the library can itself keep things in check by limiting gratuitous overloads, when an internal static if will be enough. Also, judicious use of traits can help clarify the situation. In some extreme situations, I think writing an explicit trait that "consolidates" a couple of traits at once helps: Keeping the length of the constraint in check always helps. For example, having a "std.algorithm.areComparableRanges!(R1, R2)" would help a *ton* of algorithms, while keeping things a bit clearer. Keeping them as "package" means we can write them without having to worry too much about public use. -------- Finally, one of the things I had toyed with, but never got to submitting, were "assertive traits". I had written something you could add in code, such as: //---- struct R {...} checkIsRandomAccessRange!R; void main() {} //---- With this, if R was *not* an actual random access range, it failed with an assert that said something along the lines of: R is not a BidirectionalRange because it does not have back. R is not a RandomAccessRange because it is not a BidirectionalRange. While it was quite the useful "trait", it required about 4 times the code to implement as the trait itself, and required parallel maintenance :/
Dec 05 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

 IMO, one of the initial problems is "argument type validation" 
 vs "overload resolution".
Perhaps in D we need some syntax & semantics to differentiate the two use cases, to make it more clear the difference to the compiler. Bye, bearophile
Dec 05 2013
prev sibling parent "Jason House" <jason.james.house gmail.com> writes:
On Thursday, 5 December 2013 at 13:55:30 UTC, Martin Nowak wrote:
 Ah well, this was a question for ideas.
 I don't really know to get there.
I can think of a few things: 1. The compiler could mark what made it reject a candidate. If it failed due to a template constraint it could flag the last evaluated condition. If the constraint passed, it could flag the arguments whose types did not match. Flagging could be with a special symbol. An IDE could use a different font, colors, bold etc. 2. If a constraint is a function requirement rather than a condition for matching, it could be replaced with a static assert. 3. It may be possible to embed constraints into a type specification. It might not help a lot, but may make it easier for people to parse the description easier. 4. I frequently think a lot of this constraint stuff could be done in some kind if cascading if then else style. I'm not sure how a failure would be reported, but it could greatly reduce the number of constraints.
Dec 05 2013
prev sibling parent Martin Nowak <code dawg.eu> writes:
And a fix for this particular issue.
https://d.puremagic.com/issues/show_bug.cgi?id=11691
https://github.com/D-Programming-Language/phobos/pull/1749
Dec 05 2013