Jump to page: 1 2
Thread overview
Trouble creating a formatted assert wrapper
Sep 02, 2012
Peter Alexander
Sep 02, 2012
Simen Kjaeraas
Sep 02, 2012
Peter Alexander
Sep 02, 2012
Simen Kjaeraas
Sep 02, 2012
timotheecour
Sep 02, 2012
Peter Alexander
Sep 03, 2012
Nick Treleaven
Sep 03, 2012
Nick Treleaven
Sep 02, 2012
Philippe Sigaud
Sep 02, 2012
Timon Gehr
Sep 02, 2012
Peter Alexander
Sep 03, 2012
Peter Alexander
Sep 04, 2012
Don Clugston
Sep 04, 2012
Don Clugston
Sep 03, 2012
Jonathan M Davis
September 02, 2012
One thing that's always bothered me is that I have to use std.string.format to produce useful assert messages:

assert(x == 1, format("x doesn't equal 1, it is %d", x));


Of course, I tried to solve this by producing my own assert-like function wrapper:

void myAssert(Args...)(lazy bool condition, lazy Args args)
{
    assert(condition, format(args));
}


That's all good, but the problem now is that I get the wrong file and line in the assert message, so I tried to use the default arg __FILE__ and __LINE__ trick:

void myAssert(Args...)(lazy bool condition, lazy Args args, int line = __LINE__, string file = __FILE__)
{
    if (!condition)
    {
        writeln("Assertion failed @ %s:%d", file, line);
        writefln(args);
        exit(1);
    }
}


But I can't have default arguments because of the variadic arguments!

Can anyone think of a way around this?
September 02, 2012
On Sun, 02 Sep 2012 19:14:07 +0200, Peter Alexander <peter.alexander.au@gmail.com> wrote:

> One thing that's always bothered me is that I have to use std.string.format to produce useful assert messages:
>
> assert(x == 1, format("x doesn't equal 1, it is %d", x));
>
>
> Of course, I tried to solve this by producing my own assert-like function wrapper:
>
> void myAssert(Args...)(lazy bool condition, lazy Args args)
> {
>      assert(condition, format(args));
> }
>
>
> That's all good, but the problem now is that I get the wrong file and line in the assert message, so I tried to use the default arg __FILE__ and __LINE__ trick:
>
> void myAssert(Args...)(lazy bool condition, lazy Args args, int line = __LINE__, string file = __FILE__)
> {
>      if (!condition)
>      {
>          writeln("Assertion failed @ %s:%d", file, line);
>          writefln(args);
>          exit(1);
>      }
> }
>
>
> But I can't have default arguments because of the variadic arguments!
>
> Can anyone think of a way around this?

void myAssert(int line = __LINE__, string file = __FILE__, Args...)(lazy bool condition, lazy Args args) {
    if (!condition)
    {
        writefln("Assertion failed @ %s:%d", file, line);
        writefln(args);
        exit(1);
    }
}


-- 
Simen
September 02, 2012
On Sunday, 2 September 2012 at 18:23:48 UTC, Simen Kjaeraas wrote:
> void myAssert(int line = __LINE__, string file = __FILE__, Args...)(lazy bool condition, lazy Args args) {
>     if (!condition)
>     {
>         writefln("Assertion failed @ %s:%d", file, line);
>         writefln(args);
>         exit(1);
>     }
> }

Nice. I thought of that, but for some reason I thought that you couldn't have default args before variadic args.

September 02, 2012
On Sun, 02 Sep 2012 20:46:50 +0200, Peter Alexander <peter.alexander.au@gmail.com> wrote:

> On Sunday, 2 September 2012 at 18:23:48 UTC, Simen Kjaeraas wrote:
>> void myAssert(int line = __LINE__, string file = __FILE__, Args...)(lazy bool condition, lazy Args args) {
>>     if (!condition)
>>     {
>>         writefln("Assertion failed @ %s:%d", file, line);
>>         writefln(args);
>>         exit(1);
>>     }
>> }
>
> Nice. I thought of that, but for some reason I thought that you couldn't have default args before variadic args.
>

tbh, I was unsure myself. Sometimes you should just try. :p

-- 
Simen
September 02, 2012
>>> void myAssert(int line = __LINE__, string file = __FILE__, Args...)(lazy bool condition, lazy Args args) {

Won't that create "template code bloat" ? Ie everytime myAssert is used a new function is created.

There was if I remember some discussion regarding not passing __LINE__,__FILE__ in assert related functions because of that.

If backtrace worked properly we should be able to go up the stack and get line number information when the assert fails (no time penalty when assert doesn't fail).

Another option is to use a lazy tuple argument inside myAssert instead of variadic arguments, which allows to pass line and file AFTER, without template bloat.

A related question:
In C++ we can stringify arguments and use it to provide informative asserts without duplicating code specifying a string version of the condition:
#define assert( isOK ) ( (isOK) ? (void)0 : (void)myAssert(#isOK,__LINE__,__PRETTY_FUNCTION__, __FILE__) )

Likewise for related quick debug functions:
#define DEBUG(val) myDEBUG(#val,val)

There seems to be no way of doing this currently (besides the ugly mixin(myAssertString("i==0")) which would parse the condition at CT).

Would that be possible to add?



September 02, 2012
On Sun, Sep 2, 2012 at 8:46 PM, Peter Alexander <peter.alexander.au@gmail.com> wrote:
> On Sunday, 2 September 2012 at 18:23:48 UTC, Simen Kjaeraas wrote:
>>
>> void myAssert(int line = __LINE__, string file = __FILE__, Args...)(lazy
>> bool condition, lazy Args args) {
>>     if (!condition)
>>     {
>>         writefln("Assertion failed @ %s:%d", file, line);
>>         writefln(args);
>>         exit(1);
>>     }
>> }
>
>
> Nice. I thought of that, but for some reason I thought that you couldn't have default args before variadic args.
>

IIRC, you can even have them before standard template args. Template arguments are much more versatile (or hard-working) than function arguments.
September 02, 2012
On Sunday, 2 September 2012 at 19:31:24 UTC, timotheecour wrote:
>>>> void myAssert(int line = __LINE__, string file = __FILE__, Args...)(lazy bool condition, lazy Args args) {
>
> Won't that create "template code bloat" ? Ie everytime myAssert is used a new function is created.

You can easily counter that by delegating the body to a non-template function.

Even then, it's only in non-release builds and it's a small function anyway.

September 02, 2012
On 09/02/2012 07:14 PM, Peter Alexander wrote:
> One thing that's always bothered me is that I have to use
> std.string.format to produce useful assert messages:
>
> assert(x == 1, format("x doesn't equal 1, it is %d", x));
>
>
> Of course, I tried to solve this by producing my own assert-like
> function wrapper:
>
> void myAssert(Args...)(lazy bool condition, lazy Args args)
> {
>      assert(condition, format(args));
> }
>
>
> That's all good, but the problem now is that I get the wrong file and
> line in the assert message, so I tried to use the default arg __FILE__
> and __LINE__ trick:
>
> void myAssert(Args...)(lazy bool condition, lazy Args args, int line =
> __LINE__, string file = __FILE__)
> {
>      if (!condition)
>      {
>          writeln("Assertion failed @ %s:%d", file, line);
>          writefln(args);
>          exit(1);
>      }
> }
>
>
> But I can't have default arguments because of the variadic arguments!
>
> Can anyone think of a way around this?

I don't think there is a deep reason why IFTI shouldn't succeed in this case.
September 02, 2012
On Sunday, 2 September 2012 at 20:30:26 UTC, Timon Gehr wrote:
> On 09/02/2012 07:14 PM, Peter Alexander wrote:
>> One thing that's always bothered me is that I have to use
>> std.string.format to produce useful assert messages:
>>
>> assert(x == 1, format("x doesn't equal 1, it is %d", x));
>>
>>
>> Of course, I tried to solve this by producing my own assert-like
>> function wrapper:
>>
>> void myAssert(Args...)(lazy bool condition, lazy Args args)
>> {
>>     assert(condition, format(args));
>> }
>>
>>
>> That's all good, but the problem now is that I get the wrong file and
>> line in the assert message, so I tried to use the default arg __FILE__
>> and __LINE__ trick:
>>
>> void myAssert(Args...)(lazy bool condition, lazy Args args, int line =
>> __LINE__, string file = __FILE__)
>> {
>>     if (!condition)
>>     {
>>         writeln("Assertion failed @ %s:%d", file, line);
>>         writefln(args);
>>         exit(1);
>>     }
>> }
>>
>>
>> But I can't have default arguments because of the variadic arguments!
>>
>> Can anyone think of a way around this?
>
> I don't think there is a deep reason why IFTI shouldn't succeed in this case.

Consider:

myAssert(false, "%d", 1);

What is Args? "%d", 1 could refer to the optional arguments, or the variadic arguments. Both match.
September 03, 2012
On Sunday, 2 September 2012 at 23:40:01 UTC, Peter Alexander wrote:
>
> Consider:
>
> myAssert(false, "%d", 1);
>
> What is Args? "%d", 1 could refer to the optional arguments, or the variadic arguments. Both match.

Easy: the variadic arguments are not, themselves, optional.  Match the variadic.  This kind of problem is already solved in every language with "scattering" assignments, and other such features.
« First   ‹ Prev
1 2