Assertion (software development): Difference between revisions

Content deleted Content added
mNo edit summary
m Task 70: Update syntaxhighlight tags - remove use of deprecated <source> tags
Line 8:
 
The following code contains two assertions, <code>x > 0</code> and <code>x > 1</code>, and they are indeed true at the indicated points during execution:
<sourcesyntaxhighlight lang="c">
x = 1;
assert x > 0;
x++;
assert x > 1;
</syntaxhighlight>
</source>
 
Programmers can use assertions to help specify programs and to reason about program correctness. For example, a [[precondition]]—an assertion placed at the beginning of a section of code—determines the set of states under which the programmer expects the code to execute. A [[postcondition]]—placed at the end—describes the expected state at the end of execution. For example: <code>x > 0 { x++ } x > 1</code>.
Line 19:
The example above uses the notation for including assertions used by [[C. A. R. Hoare]] in his 1969 article.<ref>[[C. A. R. Hoare]], [http://lambda-the-ultimate.org/node/1912 An axiomatic basis for computer programming], ''[[Communications of the ACM]]'', 1969.</ref> That notation cannot be used in existing mainstream programming languages. However, programmers can include unchecked assertions using the [[Comment (computer programming)|comment feature]] of their programming language. For example, in [[C (programming language)|C]]:
 
<sourcesyntaxhighlight lang="C">
x = 5;
x = x + 1;
// {x > 1}
</syntaxhighlight>
</source>
 
The braces included in the comment help distinguish this use of a comment from other uses.
Line 29:
Libraries may provide assertion features as well. For example, in C using glibc with C99 support:
 
<sourcesyntaxhighlight lang="C">
#include <assert.h>
 
Line 38:
assert(x > 1);
}
</syntaxhighlight>
</source>
 
Several modern programming languages include checked assertions – [[statement (programming)|statements]] that are checked at [[Run time (program lifecycle phase)|runtime]] or sometimes statically. If an assertion evaluates to false at runtime, an assertion failure results, which typically causes execution to abort. This draws attention to the ___location at which the logical inconsistency is detected and can be preferable to the behaviour that would otherwise result.
Line 58:
An assertion may be used to verify that an assumption made by the programmer during the implementation of the program remains valid when the program is executed. For example, consider the following [[Java (programming language)|Java]] code:
 
<sourcesyntaxhighlight lang="java">
int total = countNumberOfUsers();
if (total % 2 == 0) {
Line 66:
assert total % 2 == 1;
}
</syntaxhighlight>
</source>
 
In [[Java (programming language)|Java]], <code>%</code> is the ''[[remainder]]'' operator (''[[Modulo operation|modulo]]''), and in Java, if its first operand is negative, the result can also be negative (unlike the modulo used in mathematics). Here, the programmer has assumed that <code>total</code> is non-negative, so that the remainder of a division with 2 will always be 0 or 1. The assertion makes this assumption explicit: if <code>countNumberOfUsers</code> does return a negative value, the program may have a bug.
Line 95:
Static assertions are particularly useful in compile time [[template metaprogramming]], but can also be used in low-level languages like C by introducing illegal code if (and only if) the assertion fails. [[C1X|C11]] and [[C++11]] support static assertions directly through <code>static_assert</code>. In earlier C versions, a static assertion can be implemented, for example, like this:
 
<sourcesyntaxhighlight lang="c">
#define SASSERT(pred) switch(0){case 0:case pred:;}
 
SASSERT( BOOLEAN CONDITION );
</syntaxhighlight>
</source>
 
If the <code>(BOOLEAN CONDITION)</code> part evaluates to false then the above code will not compile because the compiler will not allow two [[Switch statement#C and languages with C-like syntax|case labels]] with the same constant. The boolean expression must be a compile-time constant value, for example <code>(sizeof(int)==4)</code> would be a valid expression in that context. This construct does not work at file scope (i.e. not inside a function), and so it must be wrapped inside a function.
Line 105:
Another popular<ref>Jon Jagger, ''[http://www.jaggersoft.com/pubs/CVu11_3.html Compile Time Assertions in C]'', 1999.</ref> way of implementing assertions in C is:
 
<sourcesyntaxhighlight lang="c">
static char const static_assertion[ (BOOLEAN CONDITION)
? 1 : -1
] = {'!'};
</syntaxhighlight>
</source>
 
If the <code>(BOOLEAN CONDITION)</code> part evaluates to false then the above code will not compile because arrays may not have a negative length. If in fact the compiler allows a negative length then the initialization byte (the <code>'!'</code> part) should cause even such over-lenient compilers to complain. The boolean expression must be a compile-time constant value, for example <code>(sizeof(int) == 4)</code> would be a valid expression in that context.
Line 131:
Consider the following example of using an assertion to handle an error:
 
<sourcesyntaxhighlight lang="c">
int *ptr = malloc(sizeof(int) * 10);
assert(ptr);
// use ptr
...
</syntaxhighlight>
</source>
 
Here, the programmer is aware that <code>[[malloc]]</code> will return a [[Null pointer|<code>NULL</code> pointer]] if memory is not allocated. This is possible: the operating system does not guarantee that every call to <code>malloc</code> will succeed. If an out of memory error occurs the program will immediately abort. Without the assertion, the program would continue running until <code>ptr </code>was dereferenced, and possibly longer, depending on the specific hardware being used. So long as assertions are not disabled, an immediate exit is assured. But if a graceful failure is desired, the program has to handle the failure. For example, a server may have multiple clients, or may hold resources that will not be released cleanly, or it may have uncommitted changes to write to a datastore. In such cases it is better to fail a single transaction than to abort abruptly.
Line 144:
Consider another version of the previous example:
 
<sourcesyntaxhighlight lang="c">
int *ptr;
// Statement below fails if malloc() returns NULL,
Line 151:
// use ptr: ptr isn't initialised when compiling with -NDEBUG!
...
</syntaxhighlight>
</source>
 
This might look like a smart way to assign the return value of <code>malloc</code> to <code>ptr</code> and check if it is <code>NULL</code> in one step, but the <code>malloc</code> call and the assignment to <code>ptr</code> is a side effect of evaluating the expression that forms the <code>assert</code> condition. When the <code>NDEBUG</code> parameter is passed to the compiler, as when the program is considered to be error-free and released, the <code>assert()</code> statement is removed, so <code>malloc()</code> isn't called, rendering <code>ptr</code> uninitialised. This could potentially result in a [[segmentation fault]] or similar [[null pointer]] error much further down the line in program execution, causing bugs that may be [[Heisenbug|sporadic]] and/or difficult to track down. Programmers sometimes use a similar VERIFY(X) define to alleviate this problem.