-
Notifications
You must be signed in to change notification settings - Fork 17
assert statement
The AssertStatement is used to test a condition, and to raise an exception if that condition evaluates to False
. For example, if a variable v
must not be Null
, then the following line of code asserts that v
is not Null
:
assert v != Null;
The condition is optional; omitting the condition is the same as using the constant False
as the condition. That means that the following simple statement will always assert:
assert;
The AssertStatement conveniently allows for both variable declaration and conditional assignment. Consider the following method:
void printNext(Iterator<String> iter)
{
@Inject Console console;
assert String s := iter.next();
console.println($"next string={s}");
}
Combined with type inference, an assertion can provide sufficient information to the compiler and to the runtime in order to ensure type safety via implicit narrowing:
String? name = loadName();
assert name != Null;
// name is now known to be a "String", not a "String?"
Int length = name.size;
By default, an assertion will be verified (i.e. "asserted") each time that it is encountered at runtime, but an assertion can be marked to run only during testing, during debugging, run only the first time that it is encountered, or even to run randomly for the purpose of sampling:
keyword | execution behavior |
---|---|
assert:once |
Evaluated only once at runtime, the first time it is encountered |
assert:rnd(x) |
Evaluated on average once every x times it is encountered |
assert:test |
Evaluation only occurs during "test" mode |
assert:debug |
Evaluation only occurs during "debug" mode; assertion results in a breakpoint |
(Note that this behavior is different from the default behavior in most languages, which is to disable assertions at runtime in order to avoid any performance penalty caused by checking assertions. The Ecstasy design reflects a conscious effort to prioritize predictability and quality by default over the performance cost of checking assertions. Assertions can be disabled at runtime by explicitly using the assert:test
keyword.)
When an assertion fails, it provides helpful runtime information that can be used to understand the cause of the failure after the fact. For example, consider the following assertion:
Int n = foo();
assert n.sign != Negative;
The resulting behavior at runtime will resemble the behavior of the following verbose code:
if (n.sign == Negative)
{
throw new IllegalState($"Assertion failed: \"n.sign != Negative\", n={n}, n.sign={n.sign}");
}
A failed assertion throws an IllegalState
exception by default.
keyword | failed assertion behavior |
---|---|
assert:arg |
throws IllegalArgument exception |
assert:bounds |
throws OutOfBounds exception |
assert:TODO |
throws UnsupportedOperation exception |
assert:debug |
debugger break-point |
The ConditionList is reachable if the AssertStatement is reachable; a missing ConditionList is treated as if the ConditionList contained a single Condition with the constant value False
. The first Condition in the ConditionList is reachable if the ConditionList is reachable. A Condition completes if is reachable and it is not the constant value False
. Each subsequent Condition is reachable if the previous Condition completes. The ConditionList completes if the last Condition in the ConditionList completes, or if a reachable Condition short-circuits. The AssertStatement completes if the assertion keyword is assert:once
, assert:rnd
, assert:test
, or assert:debug
, or if the ConditionList completes.
Definite assignment rules:
- The VAS before the ConditionList is the VAS before the
assert
statement. - If the ConditionList can short-circuit, then the VAS at each possible point of short-circuiting is joined with the VAST after the ConditionList.
- The VAS after the
assert
statement is the VAST after the ConditionList.
AssertStatement: AssertInstruction ConditionList-opt ; AssertInstruction: assert assert:arg assert:bounds assert:TODO assert:once assert:rnd( Expression ) assert:test assert:debug
From IfStatement:
ConditionList: Condition ConditionList , Condition Condition: Expression OptionalDeclaration ConditionalAssignmentOp Expression ( OptionalDeclarationList , OptionalDeclaration ) ConditionalAssignmentOp Expression ConditionalAssignmentOp: := ?=
And from VariableStatement:
OptionalDeclarationList: OptionalDeclaration OptionalDeclarationList , OptionalDeclaration OptionalDeclaration: Assignable VariableTypeExpression Name VariableTypeExpression: val var TypeExpression Assignable: Name TernaryExpression . Name TernaryExpression ArrayIndexes