On Monday, 15 May 2017 at 15:30:38 UTC, Steven Schveighoffer wrote:

Argument 2 is a string, which is not supported
file(line): Error: template foo cannot deduce function from argument
types !()(int, string), candidates are:
file(line): foo(Args...)(auto ref Args arg) if (noStringArgs!args)

I think the compiler should be able to figure this out, and report it. The if constraint is a boolean expression, and so it can be divided into the portions that pass or fail.

How? The constraint, any constraint, is de-facto user code. Even in the simple example I've provided, I would not expect the compiler to figure out what are *my* expectations on the types. I provide code for doing that, the language gives me means to that effect. What it doesn't give me though is a way to cleanly report an error. Even if the compiler was to divide the constraint into blocks and reason about them separately, it's still limited to error reporting we have now: it will report "is(T == string) was expected to be false, but it's true". Is that a good error message?

What I'd love to see is the constraint colorized to show green segments that evaluate to true, and red segments that evaluate to false. And then recursively show each piece when asked.

I think any time spent making a user-level solution will not scale. The compiler knows the information, can ascertain why it fails, and print a much nicer error message. Plus it makes compile-time much longer to get information that is already available.

I don't see how that is possible. The constraints' complexity is arbitrary, it's semantics are arbitrary. The compiler does a full semantic pass, we end up with the error messages as if it was normal program code. But the thing is, we need different error messages, because it isn't "normal" program code. In fact, what truly doesn't scale is the binary "is/isn't" solution we have now. Again, even if the compiler would display at which line/column `false` was inferred, it's not good enough, as it simply leaves the user to figure out what went wrong, without any clear hint.

Imagine also a constraint like isInputRange!R. This basically attempts to compile a dummy lambda. How would one handle this in user-code?

Umm... Exactly as it is implemented currently? With one important distinction that I would be able to report *exactly why* the type in question does not satisfy the constraint. Not an obscure

"Error: no property 'empty' for type (typename)"
"Error: expression 'foo.front()' is void and has no value"

but a descriptive

" Argument <number> does not satisfy the constraint isInputRange:"
"(typename) is expected to be an input range, but it doesn't implement the required interface:"
"   property 'empty' is not defined."
"   property 'front' is defined, but returns void."

User code can collect all the information and present it in a readable way. Compiler will never be able to. The best the compiler would do is report "T does not satisfy isInputRange". And in my opinion, that is what it should do. Adding complexity to the compiler to figure out all imaginable variations doesn't seem like a very good idea. User code is able to make all assessments it needs, it just doesn't have the ability to elaborate.

Another example:

is(typeof(x) == string) && x.startsWith("_")

The best we can expect from the compiler is print that out and say it evaluated to false. User code, on the other hand, can generate a string "x must be a string that starts with an underscore". Which one is better?

Reply via email to