Skip to content
Kavachकवच

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
require.kav: Kavach code, then what running it prints

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)
require-known.kav: Kavach code, then what running it prints
  • half(10) keeps the rule, so only the second call is refused.
  • Decimals count too: speed(120.0, -2.0) against require hours > 0.0 is refused the same way. Whole numbers compare exactly; anything with a decimal compares as Float.
  • A require with parts joined by and has 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 speed above, 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)
require-loop.kav: Kavach code, then what running it prints