Getting the error from __traits(compiles, ...)

grauzone none at example.net
Fri Nov 13 04:20:55 PST 2009


Yigal Chripun wrote:
> 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
> 

One problem with this was that arrays wouldn't automagically be ranges 
anymore. Right now, "int[] a; a.popFront();" works, because std.array 
has a global function popFront. Some old language hack turns a.popFront 
into popFront(a).



More information about the Digitalmars-d mailing list