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