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.

Reply via email to