Skip to main content


Statements in HeyVL are instructions that are interpreted sequentially and that have side-effects. They are used inside the body of procedures.


Since HeyVL is an intermediate verification language, not all statements allow an operational interpretation of their effects. All HeyVL statements should be understood through their (quantitative) verification condition semantics. These are defined in reverse order, starting from an initial verification condition and proceeding from the last statement backwards to the front. We describe the formal semantics of HeyVL statements in our paper on Caesar (cf. Section 3).


A block is a sequence of statements enclosed by curly braces. Statements may be separated by semicolons, but those can be omitted. Each block creates a local scope into which variables are declared. Blocks can be nested. For example:

x = 1
var y: UInt
y = 1 // y is not declared in this scope

Variable Declarations

A variable declaration var name: Type creates a new local variable in the current scope. A variable declaration can be combined with an assignment to initialize the variable:

var forty_two: UInt = 42


An assignment x = 39 + y evaluates the expression on the right-hand side in the current state and assigns the result to the variable on the left-hand side.

The left-hand side of an assignment may be a list of variables to unpack a tuple. For example, imagine a procedure two_numbers whose return type is (x: UInt, y: UInt). The following statement assigns the result of a call to two_numbers to x and y:

x, y = two_numbers()

If the right-hand side of the assignment is a (pure) expression, then the verification condition semantics amounts to a substitution of the left-hand side by the right-hand side.

If the right-hand side is a call to a procedure, then the assignment is translated to a combination of assert, havoc, and compare statements. See the reference on procedures for more information.

If the procedure does not have any return values, the call may be written without the equals sign and the left-hand side, i.e. simply fn(arg1, arg2).


A havoc statement can be used to "forget" previous values of variables in the following code. It also comes in a co variant.

havoc x, y, z
cohavoc a, b, c

The verification condition semantics of havoc and cohavoc create an infimum respectively supremum over the specified variables.

Assert and Assume

These statements generate binary operators in the verification condition semantics. All three statements also come in co variants. (co)assert generates an infimum respectively supremum. (co)assume generates an implication respectively co-implication.

assert 1 + x
assume 0

Reward (formerly Tick)

The reward statement accepts an expression and adds it to the current verification condition. For example,

reward 2 * x

has the following semantics: vc[reward 2 * x](f) = f + (2 * x).

tick is another name that Caesar accepts for reward.

Nondeterministic Choices

HeyVL supports two kinds of binary nondeterministic choices: The "demonic" one (if ⊓) and the "angelic" one (if ⊔).

} else {

You can also use Latex-style syntax instead of Unicode. Caesar supports \cap and \cup instead of and , respectively. (We're looking for better syntax for these statements. If you have an idea, please start a discussion.)

Boolean Choices

HeyVL supports a binary choice depending on the value of a Boolean expression:

if x + 1 == 2 {
} else {

Deprecated Statements

Caesar supports some HeyVL statements that are not part of the HeyVL language published in our OOPSLA '23 paper.


These statements were used for previous iterations of HeyVL, but may be removed from Caesar at any time.


A compare f statement corresponds to an abbreviation of validate; assume f.

The dual cocompare f statement corresponds to an abbreviation of covalidate; coassume f.


We have a negate and an conegate statement, whose semantics correspond to HeyLo's negations.

The validate statement corresponds to conegate; conegate and covalidate corresponds to negate; negate.

It is recommended that you avoid negations for the reasons detailed in the warning below.


Negation statements in HeyVL break monotonicity, an important property of HeyVL semantics that is required for sound (co)procedure calls. If negations are used in such a way that monotonicity is broken, then (co)procedure calls are unsound. Refer to our OOPSLA '23 paper for details on monotonicity and soundness of (co)procedure calls.