www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Prettiful error messages with templates

reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
I'm currently using this somewhat verbose approach to template error  =

messages:

debug
{
   int opAdd(U, int line =3D __LINE__, string file =3D __FILE__)(U args)=

   {
     static if (__traits(compiles, somethingHere)) // check if this  =

template should have been instantiated at all
     {
       pragma(msg, "Failed instantiating template in file " ~ file ~ " o=
n  =

line " ~ toString(line)); // for a more prettiful error message. Could  =

easily put this in the assert
       static assert(0);
     }
     // Do actual work here. Don't use line or file arguments.
   }
}
else
{
   int opAdd(U)(U args)
   {
     // Do actual work here.
   }
}

Now, what are the problems with this approach?

1. It is rather verbose.
2. Code duplication.
3. Template bloat for the debug version. For every time + is used, a new=
  =

instantiation is created. I have duplicated the code to avoid this in  =

release builds.
4. toString(int) is not CTFE-compatible.

Good things:

It gives exact error messages, telling the user what went wrong and wher=
e.

So, what do I want?

An easier way of doing this. If it weren't for #3 (which might be a  =

limitation of the linker or compiler), I could avoid the code duplicatio=
n,  =

so I guess that's the biggest problem.

Any ideas?

-- Simen
May 04 2008
parent Lutger <lutger.blijdestin gmail.com> writes:
Not sure how this works in D2 and it doesn't solve the biggest problems but
here's a possible begin:

char[] assertCompiles(uint line, char[] file, char[] code)
{
    return `debug { static if (!__traits(compiles, ` ~ code ~ `))` 
            `{` 
                `pragma(msg, "Failed instantiating template in file ` ~ file
~ ` on line ` ~ ctfeToString(line) ~ `");` 
                `static assert(false);` 
            `}}`;
}

iirc I adapted ctfeToString from phobos' std.string: 

const char[10] digits    = "0123456789";            /// 0..9

/// ditto
char[] ctfeToString(ulong u)
{
    char[] buffer;
    auto buflen = ulong.sizeof * 3;
    while (buflen--)
        buffer ~= ' ';
    int ndigits;

    ndigits = 0;
    if (u < 10)
    // Avoid storage allocation for simple stuff
        return digits[u .. u + 1];
    else
    {
        while (u)
        {
            uint c = (u % 10) + '0';
            u /= 10;
            ndigits++;
            buffer[buffer.length - ndigits] = cast(char)c;

        }
        return buffer[buffer.length - ndigits .. buffer.length].dup;
    }
}

it'll help a bit with the verbosity, used as:

int opAdd(U, uint line = __LINE__, char[] file = __FILE__ ) (U args)
{
    mixin( assertCompiles(line, file, code));
    ...
}


Will you post back when you found some good solutions? Thanks.

Good luck and happy hacking ;)
May 05 2008