On the subject of error messages
Stanislav Blinov via Digitalmars-d
digitalmars-d at puremagic.com
Mon May 15 17:14:04 PDT 2017
On Monday, 15 May 2017 at 20:55:35 UTC, Steven Schveighoffer
wrote:
> On 5/15/17 4:24 PM, Stanislav Blinov wrote:
>> On Monday, 15 May 2017 at 19:44:11 UTC, Steven Schveighoffer
>> wrote:
>
>>> 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.
>
> I'm going to snip away pretty much everything else and focus on
> this.
>
> The compiler absolutely 100% knows, and can demonstrate,
> exactly why a template constraint failed. We don't have to go
> any further, or make suggestions about how to fix it.
In complex constraints, that is not enough. When we have loops
(i.e. over arguments, or over struct members), would it report
the iteration/name? Would it know to report it if `false` came
several levels deep in the loop body? Would it know that we
actually *care* about that information? (*cough* C++ *cough*
pages and pages of error text because of a typo...)
When we have nested static ifs, it's important to see, at a
glance, which parts of the combination were false. Again, if
they're several &&, || in a row, or nested, pointing to a single
one wouldn't in any way be informative.
When we have tests using dummy lambdas, are we to expect users to
immediately extract the lambda body, parse it, and figure out
what's wrong?
> Just output what exactly is wrong, even if you have to recurse
> into the depths of some obscure template isXXX, and all it's
> recursively called templates, I can get the correct
> determination of where either my type isn't right, or the
> constraint isn't right.
Please look over my isMovable example (I'm not sure if you caught
it, I posted it as a follow up to my other reply). Suppose the
`false` is pointed at by the compiler:
> else static if (is(T == struct) &&
> (hasElaborateDestructor!T ||
> hasElaborateCopyConstructor!T)) {
> foreach (m; T.init.tupleof) {
> static if (!isMovable!(typeof(m)) && (m == m.init)) {
> return false;
> ^
> |
> }
> }
> return true;
> } else
That is very, *very* uninformative. I don't know which member it
was, I don't know which part of the conditional was false. I
don't know which part of the conditional further up was true.
Would the compiler know to tell me all that? Would it know to
test further, to collect *all* information, so that I don't have
to incrementally recompile fixing one thing at a time?
Most importantly, as a user who sees this for the first time, I'd
have no idea *why* those checks are there. I'd have no context,
no grounds to base my reasoning on, so I'd either have to jump
back to docs to see if I missed a corner case, or start
spelunking code that I didn't write, which is always so fun...
Thing is, the compiler is exactly in that position. It doesn't
read the docs, ever :) It's always spelunking code written by
someone else. It can't tell what the constraint, as a unit, is
*actually* testing for. It doesn't care that we shouldn't
destructively move structs with const members. So it wouldn't be
able to tell me either. All it will do is report me that that
false was returned on that line, and (hopefully), some additional
info, like member type and name.
More information about the Digitalmars-d
mailing list