Assertions
assert checks a condition while a program runs. It is a statement like any
other, so it works in ordinary code as well as in a test block.
The assert Statement
assert checks that a condition is true. If it is false, the program traps.
First it writes a message to standard error, showing the condition's source and
the values of its operands as power-assert does, unless the build drops it (see
Assertions Are Never Removed).
// Traps if x is not greater than 0.
assert x > 0;
// Also assert can take an optional message.
assert x > 0, "x must be checked elsewhere";
Evaluation
assert evaluates its condition exactly as the surrounding code would, so a
guarded operand never runs when its guard fails. An operand the run did not
reach is reported as <not evaluated>.
let list: List<i32> = [1, 2, 3];
let i = 99;
assert i < list.len() && list[i] == 1;
// condition: i < list.len() && list[i] == 1
// i: 99
// list: [1, 2, 3]
// list.len(): 3
// i < list.len(): false
// i: <not evaluated>
// list[i]: <not evaluated>
// list[i] == 1: <not evaluated>
The Failure Message
Each captured operand is rendered with Inspect (:?), so a long String or
List operand is cut at Inspect's default length and marked where it was cut
(see Inspect Truncation). This keeps a
failure readable. The optional message is an ordinary expression, formatted by
whatever template specifiers it uses. Display is never cut, so formatting a
value into the message yourself shows all of it.
Assertions Are Never Removed
No build removes an assertion. At every optimization level the condition is
evaluated, and a false one traps. An invariant an assert states therefore
holds in every build, so a program can rely on assert to protect its state.
Checking costs run time. The part that can be dropped is the power-assert
overhead: capturing the operands and building the failure message. Under
-f bare-asserts a failed assertion traps without printing anything, and
nothing that captures or builds the message is compiled in. -Os turns it on,
and -f no-bare-asserts turns it back off:
wado compile -Os app.wado # a failed assert traps silently
wado compile -Os -f no-bare-asserts app.wado # the message is kept
wado compile -O2 -f bare-asserts app.wado # silent at -O2 too
Contract Checks
A build may check the contracts of the standard library's _unchecked
functions (see Behavior Classes). A
checking build traps on a call outside the contract, as a failed assertion
does, message included. A build that does not check evaluates nothing, and the
compiler does not assume the contract holds: the violation keeps the class the
function's documentation gives it.
-f contract-checks and -f no-contract-checks choose. Without either, the
test world checks at every optimization level, and any other world checks at
-O0 only:
wado test app.wado # checks
wado test -f no-contract-checks app.wado # does not
wado run -O0 app.wado # checks
wado run app.wado # does not (-O2)
wado compile -O2 -f contract-checks app.wado # checks
