Getting the error from __traits(compiles, ...)
Yigal Chripun
yigal100 at gmail.com
Thu Nov 12 22:32:18 PST 2009
Bill Baxter wrote:
> On Thu, Nov 12, 2009 at 1:00 PM, Walter Bright
> <newshound1 at digitalmars.com> wrote:
>> Walter Bright wrote:
>>> Bill Baxter wrote:
>>>> Any other thoughts about how to get the failure info? This is
>>>> probably the main complaint against __traits(compiles), that there's
>>>> no way to find out what went wrong if the code doesn't compile. Often
>>>> it can just be a typo. I know I've spent plenty of time looking at
>>>> static if(__traits(compiles, ...)) checks that weren't working only to
>>>> discover I switched an x for a y somewhere. Or passed the wrong
>>>> number of arguments.
>>> I agree it's a problem. Perhaps we can do:
>>>
>>> __traits(compiles_or_msg, ...)
>>>
>>> which would print the error messages, at least making it easier to track
>>> down.
>> Eh, scratch that dumb idea. Just remove the __traits(compiles, ...) and
>> replace it with ..., and you'll get the message!
>
> Maybe that is enough combined with a const code snippet
>
> enum code = q{
> R r; // can define a range object
> if (r.empty) {} // can test for empty
> r.popFront; // can invoke next
> auto h = r.front; // can get the front of the range
> }
> static if (__traits(compiles, mixin(code))) {
> mixin(code);
> }
> else {
> pragma(msg, "Unable to instantiate code for type
> T=`"~T.stringof~"`:\n "~ code);
> pragma(msg, "Compiler reports:" );
> mixin(code);
> }
>
> But I was really hoping for a separation of Interface definition and
> Interface verification. With the above you'll have to have two
> templates for every interface, like isForwardRange!(T) (evals to
> bool) and assertIsForwardRange!(T) (reports the compiler error or is
> silent). Hmm.... unless
>
> template assertIsInputRange(T, bool noisy=true) {
> enum code = q{
> R r; // can define a range object
> if (r.empty) {} // can test for empty
> r.popFront; // can invoke next
> auto h = r.front; // can get the front of the range
> };
> static if (!__traits(compiles, mixin(code))) {
> static if (noisy) {
> pragma(msg, "Type T=`"~T.stringof~"` doesn't support
> interface:\n "~ code);
> pragma(msg, "Compiler reports:" );
> }
> mixin(code);
> }
> }
>
> template isInputRange(T) {
> enum bool isInputRange = __traits(compiles, assertIsInputRange!(T, false));
> }
>
> And then we could wrap the whole shebang in a fancy code-generating
> string mixin and define things like the above using:
>
> mixin(DefineInterface(
> "InputRange",
> q{
> R r; // can define a range object
> if (r.empty) {} // can test for empty
> r.popFront; // can invoke next
> auto h = r.front; // can get the front of the range
> }));
>
> mixin(DefineInterface!(assertIsInputRange)(
> "ForwardRange",
> q{
> R r1;
> R r2 = r1; // can copy a range object
> })));
>
> Writing DefineInterface is left as an exercise for the reader. :-)
> But it looks do-able.
> And DefineInterface could take a variadic list of assertIsXXX template
> aliases and generate code to check each one.
>
> --bb
I really wish this was folded into the language by allowing structs to
implement interfaces.
interface Range(T) {
bool empty();
void popFront();
T front();
}
struct MyRange(T) : Range!(T) { ... } // checked by compiler
More information about the Digitalmars-d
mailing list