Skip to content

Allow assert() with custom error message #1303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mdsteele opened this issue Jul 30, 2018 · 3 comments
Closed

Allow assert() with custom error message #1303

mdsteele opened this issue Jul 30, 2018 · 3 comments
Milestone

Comments

@mdsteele
Copy link
Contributor

Many other languages allow adding a custom error message to assertions, to provide better context if the assertion fails. For example:

assert(x > 0, "x must be positive, but it was {} instead", x);

I've been finding myself missing this in Zig. I don't know whether it's possible to support both assert(cond) and assert(cond, fmt, ...) with the same function name, but if not, then we could have, say, assert(cond) and assertMsg(cond, fmt, ...).

@andrewrk andrewrk added this to the 0.4.0 milestone Jul 30, 2018
@andrewrk
Copy link
Member

I believe this is related to #1304. One consideration here is whether the assert is going to invoke unreachable or @panic. They're the same thing in Debug and ReleaseSafe mode, but in ReleaseFast and ReleaseSmall modes, unreachable is a hint to the optimizer (because it invokes undefined behavior) and @panic is guaranteed to abort.

@PavelVozenilek
Copy link

PavelVozenilek commented Jul 30, 2018

There's precedent for such a desirable feature. Long, long ago someone came up with an idea of advanced assert in C++. Basically, when assert fires, it could also print multiple interesting values.
http://www.drdobbs.com/cpp/enhancing-assertions/184403745

It was very clever, but unfortunately, it severely impacted compilation time, so the effort to get it into Boost was abandoned.

Some notes about Zig implementation:

  1. Such assert should evaluate its second and next parameters lazily, to avoid performance/memory impact.

    assert(x > 0, "foo = {}", foo());

    would became (in C like-code):

    #if ASSERTS_ENABLED
    if (x <= 0) {
      assert(false, "foo = {}", foo());
    }
    #endif
    
    
  2. Tested values should print out implicitly:

    assert(foo() < bar());

    would be equivalent of:

    #if ASSERTS_ENABLED
    int  foo_result, bar_result;
    foo_result = foo();
    bar_result = bar();
    assert(foo_result < bar_result, "foo = {}, bar = {}", foo_result, bar_result);
    #endif
    
    
  3. If some function is called twice, the compiler should rearrange the code to call it only once:

    assert(foo() > 0, "foo() returned ", foo());

    should became:

    #if ASSERTS_ENABLED
    int  foo_result;
    foo_result = foo();
    assert(foo_result > 0, "foo returned", foo_result);
    #endif
    
    
    
  4. It should be possible to omit the formatting string altogether:

    assert(x > 0, y, z);

    should automagically transform itself into:

    assert(x > 0, "x = {}, y = {}, z = {}", x, y, z);

@andrewrk
Copy link
Member

This is solved in c2db077 which makes the distinction between std.debug.assert and std.testing.expect. The testing module can have any number of handy functions, including ones that do var args printing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants