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