4

Some languages and libraries can associate assertion messages with assertions. Such assertion messages are included in error messages when the assertion does not hold. Examples are Java, Class::Contract, ContractLib and to some extent Eiffel itself (labels).

If I haven't overlooked something, assertion messages can either (1) describe the assertion or (2) describe the situation when the assertion does not hold:

// describes the assertion
assert !socketChannel.isBlocking() :
    "the socket must not be blocking to be selectable";

// describes the situation when the assertion does not hold
assert !socketChannel.isBlocking() :
    "the socket is blocking and thus not selectable";

Both types of assertion messages could be replaced by comments.

Oracle's documentation leaves the semantics to the programmer and states that the purpose of assertion messages is to help the programmer. So it presents the choice as a personal preference. However, I would like to be more objective about this choice. My current thinking is this as follows: Ideally, the assertion is self-explanatory and needs no description. If it does, it is better to describe it in a comment than in an assertion message as the description refers to code. Users should never see assertion errors (uncaught exception in general) and therefore the assertion message does not need to describe what went wrong.

Is there an additional explanation of which type of assertion messages is better or why both types are unnecessary (other than personal preference)?

5
  • 2
    Neither kind of assertion can be replaced by comments because comments aren't executable! – RubberDuck Nov 4 '15 at 0:29
  • Also, users don't ever see assertions. They're "optimized" away by the compiler when building for release. – RubberDuck Nov 4 '15 at 0:30
  • 1
    @RubberDuck The software is released with assertions enabled. A crash report component captures and reports violated assertion before displaying an error report confirmation and terminating the software. Assertions are used to indicate situation that shouldn't happen and indicate a bug. Moreover, assertion message aren't executable either, so I don't understand your comment. – user3998276 Nov 4 '15 at 14:11
  • 2
    stop that now. It's an abuse of the feature. What you want is an exception, not an assertion. Assertions are for debugging. – RubberDuck Nov 4 '15 at 17:23
  • 1
    @RubberDuck, what you want is an assertion that stops the program dead in its tracks. In many situations. Maybe not in your work situation, but in other's. – gnasher729 Nov 4 '15 at 20:41
6

You seem to be dividing the people that may encounter the errors thrown from the assertion into two categories:

  1. You, which should be able to understand what went wrong from the auto-generated message, and which will start debugging from the definition
  2. End users, which should have never encountered the assertion in the first place, and which will mail the assertion text to you / open a ticket in your bug tracker / stop using your product and switch to the competitor / sue you for causing them to lose valuable commercial data

This may or may not be true for your own project, but in most reasonably sized projects other categories of people exist:

  • Other programmers that use your library
  • Your teammates, working on other parts of the project
  • Contributors to open source projects, limiting their modifications to specific parts of the project
  • You yourself, two months after the last time you've hacked around that area of the project

These people are fundamentally different from the original two categories:

  1. Unlike you, they are not familiar with the part of the code where the assert resides. Looking at unfamiliar code written by other peoples is rarely a very enjoyable pastime - even if that code is well designed and documented.
  2. Unlike your end users, they don't have the privilege of not having to understand the assertions. They are developers, and it's perfectly normal for developers to use functions/classes/modules wrong and trigger assertions there.

So, these people will see the assertions and will need to understand them(because it might be their code that did something wrong), but they won't be as comfortable as you going to the actual assert statement, looking at it's surrounding, and understanding what was going on. If you were already going to write a comment describing what (you believe) went wrong when that assertion is triggered, why not put it in the assertion's error message and make these coders' lives easier?

1

Regarding what the message associated should describe, you should stick with the assertive form which express what is expected. This is not only a preference: if you try explaining what went wrong, you'll have to negate your logic in your string and it might in fact become false, or ambiguous. Just explain what was supposed to happen.

But this is not enough.

You should provide more context and make your assumptions even more explicit by telling us why the assertion is supposed to hold. In no specific language:

assert (sensor >= threshold) : 
  "Sensor is assumed to be above threshold at this point
   because we are in a tightly optimized function (well, 
   that's what Greg always claims) and the caller is 
   responsible for doing sanity checks (see check-sensor
   function)."

(though the passive-aggressive remark, while useful, should probably be removed)

If you want to prevent users from seing assertions and/or exceptions, why stop at the string? comment the whole expression! More seriously, you should handle your exceptions whenever you can provide a useful feedback and possibly alternate paths. Sometimes your code is simply wrong despite your effort and your system will let internal error message bubble up to the highest-level of the code. But this is still fine, you can catch and log them before they reach the screen.

1

As an end user, I couldn't care less about an assertion. It's meant to protect 'your implementation'. Hence I would like the message to tell me what I did wrong and/or what should I do to fix it.

There is absolutely nothing wrong in leaving the message out if the "auto generated assertion message" satisfies my requirement above, e.g. the two assertions you provided in the question.

But I wouldn't be happy if the assertion is something like _n > (0.75 * _m) && _free_nodes < (0.3 * _max_size). In this case I would appreciate a message saying:

Please check the capacity limits set on this graph at the time of creation. Either increase the max capacity or respect it.

P.S. Don't try to decipher the assertion condition. I just wanted to write something an end user won't understand.

1

Users should never see assertion errors (uncaught exception in general) and therefore the assertion message does not need to describe what went wrong.

In a lot of contexts, assertions are best used for spotting bugs (programmer errors) -- things that should never happen. They're ideally caught in internal testing before they reach the hands of the user (and often serve that purpose of spotting more issues upfront during internal testing instead of leaking the issues to the users). They're different from exceptional control flow which is typically the result of an external error outside of the programmer's control (trying to load a corrupt file, e.g.) and not actually a bug.

In the unlikely (but not always impossible) event that they can and do end up reaching the user, it should be obvious what kind of assertion failure message looks less horrid to an ordinary user.

Is there an additional explanation of which type of assertion messages is better or why both types are unnecessary (other than personal preference)?

Maybe it'd help to run into more assertion failures?

As an example, I might run a debug build of an application in a team environment after acquiring new hardware and drivers and run into an assertion failure like:

"Failed to allocate vertex buffer object!".

Aha! Instantly I know the problem is in the GPU code. That might not even be my responsibility, it might be Fred's code. Now I can just bounce the issue to Fred without even studying his source code.

If I'm in control of the code, it still tends to give me a lot of information about what happened at a glance which can be quite soothing.

The alternative with comments is to dig into the source code, to the exact line of code and source file in which the assertion failed, and then read the comments, with an assertion failure message like:

Assertion failure in some_path/something/some_source.ext: 119: assert(success).

And even that little moment of suspense where you now dig into that cited source file and go to the specified line number to try to figure out what the hell happened can be quite stressful, especially since assertions are never supposed to fail (but still do sometimes anyway, making them really unpleasant surprises).

In general it's a lot more stressful to me if I enter my apartment with the lights off and people just start yelling "RARRRRRGH!" at the top of their lungs before singing happy birthday. It's far less stressful if they skip that part and just start singing happy birthday. "Phew, that's why they surprised me!"

I'd say it's quite a stress reliever at the very least to see more information relating to why an assertion failed immediately in the same sense without digging into the source file where it occurred after getting that jolting surprise.

In the same sense, if your code fails to compile, you don't want to have to go look up a specific line number of an external file containing documentation to get even a remotely human description of why the compilation failed. It's far more relaxing to know the issue sooner and get at least a little bit more information about why this unanticipated failure occurred as quickly as possible since it'll leave you in a pretty foul mood otherwise. Imagine if compilation errors showed you a hex dump followed by a citation of a specific line number of an external document file through which you can look up the cause of the error.

For fail messages, I'd say the most soothing information is often contextual information giving you a good clue as to where the failure occurred (from a high-level standpoint that doesn't require looking at a specified line number of a specified source file) and not merely why it occurred, since that's typically the first gut reaction when encountering an annoying assertion failure ("Where the hell did that happen?" which can sometimes be an even more immediate concern than why it happened).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.