On Invariants.
What is an invariant?
- The specification of a program should be its class invariants
- Aim to write programs so that you cannot create invalid objects or data.
I’ll use Rust as the language to describe the concepts behind this post, but try to make it accessible to those using other languages.
We can start with a simple object, such as a circle. A circle is completely defined by it’s radius. As long as our radius is positive, we have a valid circle:
#[derive(Debug)]
struct Circle {
radius: f64
}impl Circle {
fn new_option (radius: f64) -> Option<Circle> {
if radius > 0.0 {
Some(Circle {radius: radius})
}
else {
None
}
} fn new_assert (radius: f64) -> Circle {
assert!(radius > 0.0);
Circle {radius: radius}
}
}
For this example, we have two constructors: new_option
and new_assert
. They are two versions of the same constructor. The new_assert
function takes a radius, returns a circle if the radius is positive, and kills the program if it is not. The new_option
function takes a radius, returns a circle if the radius is positive, and returns nothing if it is not. Discussion on which method is more appropriate to use is left for another time.