On Monday, 15 May 2017 at 19:44:11 UTC, Steven Schveighoffer wrote:
On 5/15/17 1:16 PM, Stanislav Blinov wrote:
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.

Code evaluated at compile time. It actually has to evaluate each of the pieces, and knows why the whole if statement fails exactly.

The constraint:

void foo(T)(T t) if (cond1!T && cond2!T && cond3!T), the compiler knows both what each of those terms evaluate to, and therefore which ones are causing the thing not to be enabled.

Yes, that is what it is: code. Code that follows language rules, not some ADL. No mater how expressive the language is, it is still code. And if, on compile error, the compiler shows me the code from the foreign library that I thought I was using correctly, I'm supposed to now do what the compiler just did and figure out where I made a mistake.

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 think you misunderstand, your example would still not compile, and instead of "here are all the ones I tried", it's "here are all the ones I tried, and in each case, I've highlighted why it didn't work". [...]
[...] Then I need to figure out why it's not working.

It is exactly for the cases where the logic is more complex than a simple test that my proposal is for. I'm not suggesting to abuse it throughout.

now: it will report "is(T == string) was expected to be false, but it's
true". Is that a good error message?

Yes. It's a perfect error message actually. What is confusing about it?

There is no context. To get at context, I have to look at the code.

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.

It has to know. It has to evaluate the boolean to see if it should compile! The current situation would be like the compiler saying there's an error in your code, but won't tell you the line number. Surely it knows.

It "knows" it evaluated false. It doesn't know how to give user a digestible hint to make that false go away.

Today we get an error that:

void foo(R)(R r) if(isInputRange!R)

doesn't compile for the obvious (to you) range type R. What it doesn't tell you is anything about why that doesn't work. We don't even get the "no property empty" message.

Exactly my point.

Let me give you a real example. The isForwardRange test used to look like this:

template isForwardRange(R)

I'm going to need to digest that.


No, the compiler just needs to detail its evaluation process that it's already doing.

That is not enough. Failure may be X levels deep in some obscure chunk surrounded by static ifs and and a bunch of wonky tests involving attempted lambda compilations (which I'd have to parse and "compile" in my head in order to try to understand what failed).

If the constraint doesn't actually match the pragma message, you get MISLEADING messages, or maybe messages when it actually compiles. Much better to have the compiler tell you actually what it's doing.

The library author is free to take as many passes over their messages as they deem necessary. They can be as vague or as precise as needed. It is their responsibility.

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.

It can say that is(typeof(x) == string) is false, or x.startsWith("_") is 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?

My version. Is x not a string, or does x not start with an underscore? Not enough information in your error message. And it doesn't give me more information than the actual constraint code, it's just written out verbosely.

I've already demonstrated that the message text can be made as precise as is required for a concrete use case, there's no need to nitpick ;) I could as easily report either:

"x is not a string"

or

"string x should start with an underscore".

or

"Argument 10 (int) is not a string. This method is only callable with strings that start with an underscore".

"Value of argument 10 (string) does not start with an underscore. This method is only callable with strings that start with an underscore".

I, as a responsible author, can decide what amount of information must be presented. It could be accompanied by code, I'm not against that. The main point is to explain the error without *requiring* the user to use their head as a compiler.

Reply via email to