Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

assert(false) in D language

Tags:

assert

d

TDPL describes a behavior of assert(false); statement. Such assertion is not removed from release build (as all other assertions) and, actually, stops the program immediately. The question is why? Why such confusing behavior? They might add halt(); or something like that to be able to stop the program.

Sometimes, I use the following construction in C++ code:

if (something_goes_wrong)
{
   assert(false);
   return false;
}

Obviously, such construction is not possible in D.

UPDATE

To be clear. The question is why int x=0; assert(x); won't crash a release version of a program, but assert(0); will? Why such strange language design decision?

like image 287
Stas Avatar asked Aug 06 '11 16:08

Stas


People also ask

What happens if assert fails in C?

The C language provides an <assert. h> header file and corresponding assert() macro that a programmer can use to make assertions. If an assertion fails, the assert() macro arranges to print a diagnostic message describing the condition that should have been true but was not, and then it kills the program.

What does assert 0 mean?

assert(0) or assert(false) is usually used to mark unreachable code, so that in debug mode a diagnostic message is emitted and the program is aborted when the supposedly unreachable is actually reached, which is a clear signal that the program isn't doing what we think it is.

What does assert mean in coding?

The assert keyword is used when debugging code. The assert keyword lets you test if a condition in your code returns True, if not, the program will raise an AssertionError. You can write a message to be written if the code returns False, check the example below.

Does assert call abort?

The assert macro prints a diagnostic message when expression evaluates to false (0) and calls abort to stop program execution. No action is taken if expression is true (nonzero). The diagnostic message includes the failed expression, the name of the source file and line number where the assertion failed.


2 Answers

that's older than D and it's generally used to tell the compiler you don't expect to ever get to that point in the code for because that would mean that something is very wrong in the code

typical use is like this

MyStruct foo(){
    foreach(s;set){
        if(someConditionGuaranteedToHoldForAtLeastOne(s))
            return s;
    }
    //now what I can't return null;
    assert(0);//tell the compiler I don't expect to ever come here
}
like image 76
ratchet freak Avatar answered Nov 10 '22 06:11

ratchet freak


An assertion is used to verify something about the state of your program at a particular point in the program. If the assertion fails, then there is a bug in the program, and it makes no sense to continue the execution of the program. But it does cost something to run an assertion - especially one that involves making function calls - so you usually disable them in release mode (-release for dmd does this automatically). You run your program and test it in debug mode and hopefully you hit any states that result in assertions failing so that you can catch and fix those bugs. Then you hope that you've caught them all and that nothing terribly bad happens in release mode if you didn't.

But what about entering code paths which should never be reached under any circumstances? That's where assert(0) comes in.

It functions like a normal assertion without -release, so you get nice stack traces and all that when you hit it, but because it's something that should not only never happen but would result in a completely invalid code path, it's left in in release mode but changed to a halt instruction. Classic places of where to use it would be cases such as

switch(var)
{
    ...
    //various case statements that should cover all possible values of var
    ...

    default:
        assert(0, format("Invalid value for var: %s", var));
}

where the default case should never be hit, and if it is, the logic in your function is wrong, or

string func(int i) nothrow
{
    try
        return format("%s", i);
    catch(Exception e)
        assert(0, "Format threw. That should be impossible in this case.");
}

where as long as the logic of func is correct, it should be impossible for it to throw, but it called a function which can throw under some set of circumstances (just not these), so you have to use a try-catch block to make the compiler happy. You then put an assert(0) in the catch block so that you catch it if it really can throw.

The classic case for assert(0) is actually used by the compiler itself - and that is to insert it at the end of a function which doesn't end with a return statement so that the code execution does not attempt to continue if your code's logic is incorrect and you somehow end up at the end of the function anyway.

In all such cases, you're dealing with a code path which is impossible to hit as long as your code is correct, but it's a safety net in case you got your logic wrong. The advantages of using assert(0) for this over a naked halt instruction are that when -release is enabled, you get a proper stack trace, and you can have a nice error message with it. Then when -release is enabled, it gets turned into a halt instruction, so you're guaranteed that your program won't get itself into an invalid state by getting past the line with the assert(0).

You use normal assertions for stuff that you want to verify in debug mode but not in release mode, and you use assert(0) for code paths that you want to guarantee are never hit in any mode.

like image 24
Jonathan M Davis Avatar answered Nov 10 '22 05:11

Jonathan M Davis