Contracts: require
● Intermediate3 min
require states what callers must make true. A call that breaks it stops the program, naming the rule.
fn speed(distance: Float, hours: Float) -> Float
require hours > 0.0
{
distance / hours
}
fn main() {
for hours in [2.0, 0.0] {
print(speed(120.0, hours))
}
}The program ran, then stopped with a panic:
kavach run require.kav
60.0panic: contract failed: require hours > 0.0
In the terminal, the message also shows the function, the line and the values involved, so the caller's bug is easy to find.
Found before it runs
When the compiler knows what a call passes (a literal, a const set to one, or a let set to one with nothing in between that may change it), and the require compares a parameter with a number, a call that would always break it is a compile error, with the contract and the value:
fn half(owed: Int) -> Int
require owed > 0
{
owed / 2
}
fn main() {
print(half(10))
print(half(-4))
}The compiler refused the program:
kavach run require-known.kav
error: this call always breaks `require owed > 0` of `half`: `owed` is -4 (spec 7.7)half(10)keeps the rule, so only the second call is refused.- Decimals count too:
speed(120.0, -2.0)againstrequire hours > 0.0is refused the same way. Whole numbers compare exactly; anything with a decimal compares asFloat. - A
requirewith parts joined byandhas each part checked, and the message names every value involved. - Standard-library contracts count too:
random.int(5, 5)is refused the same way. - A value the compiler can't know, read from input or worked out in a loop as in
speedabove, is still checked when the program runs.
A for over a range of known numbers passes its first and last values, when nothing in its body can leave early. The message names the first value that breaks the rule:
fn half(owed: Int) -> Int
require owed > 0
{
owed / 2
}
fn main() {
for i in -3..0 {
print(half(i))
}
}The compiler refused the program:
kavach run require-loop.kav
error: this call always breaks `require owed > 0` of `half`: `owed` is -3 (spec 7.7)