User-defined template error messages

luckoverthere luckoverthere at gmail.cm
Sun Jan 13 19:38:01 UTC 2019


On Sunday, 13 January 2019 at 18:54:52 UTC, Andrei Alexandrescu 
wrote:
> We've had this problem for a long time - template doesn't match 
> because of a complex constraint, the error message is 
> unhelpful, and the user doesn't know what to do.
>
> I think this is an important missed opportunity. One of the 
> promises of Design by Introspection is it raises the level of 
> error messages from mere built-in canned messages to 
> higher-level messages expressed in terms of problem-space 
> entities.
>
> A simple way to address this would be with a two-pronged 
> proposal:
>
> 1. Allow multiple "if" constraints in a template. All "if" 
> constraints must match. This means a natural way to write 
> complex constraints is a conjunction of simpler constraints.
>
> 2. Extend the syntax to:
>
> if (condition) else string
>
> The string (which crucially can be a CT expression involving 
> template parameters) is the error message that would be 
> displayed should the condition be false.
>
> When an overload set is being looked up, if no match then the 
> string corresponding to the first failed condition in each 
> overload is printed as the error message.
>
> Example from std. Current sig:
>
> InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, 
> InputRange2 tgt)
> if (isInputRange!InputRange1 && isInputRange!InputRange2
>         && is(typeof(move(src.front, tgt.front))));
>
> With the proposal:
>
> InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, 
> InputRange2 tgt)
> if (isInputRange!InputRange1)
> else InputRange1.stringof ~ " must be an input range"
> if (isInputRange!InputRange2)
> else InputRange2.stringof ~ " must be an input range"
> if (is(typeof(move(src.front, tgt.front))))
> else "Cannot move from the front of "~InputRange1.stringof~
>     " to the front of "~InputRange2.stringof;
>
> Larger but offers the benefits of beautiful error messages.
>
>
> Andrei

I don't really like that syntax, it changes the meaning of what 
if/else mean and how they behave from everything else.

This makes more sense logically and is in line with how if/else 
functions. Though still not 100% accurate as the else should 
technically be with the last if statement.

InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, 
InputRange2 tgt)
if (!isInputRange!InputRange1) InputRange1.stringof ~ " must be 
an input range"
if (!isInputRange!InputRange2) InputRange2.stringof ~ " must be 
an input range"
if (!is(typeof(move(src.front, tgt.front))))
     "Cannot move from the front of "~InputRange1.stringof~
     " to the front of "~InputRange2.stringof;
else
{
     // implementation ...
}

Still this sort of syntax only really works well if the statement 
is expressed using &&'s but you can't reduce it if you need || 
logic. All of the || logic would need to be in the same if 
statement. Then determining which condition was false would 
require addition if statements to provide a proper message.

We could just go with something like what is being done with 
asserts.

> InputRange2 moveAll(InputRange1, InputRange2)(InputRange1 src, 
> InputRange2 tgt)
> if (isInputRange!InputRange1 && isInputRange!InputRange2
>         && is(typeof(move(src.front, tgt.front))));

For the above case detect what part of the if statement failed. 
The error message would be something like

<function declaration>
Arguments don't match as isInputRange!TheRangeTypeUsed is false.






More information about the Digitalmars-d mailing list