I like to check the preconditions of a function explicitly by means of code (instead of only documenting them). Of course this incurs a time-penalty.
When being extremely cautious every function in a call-chain will always check its preconditions. But for a function down in the call-chain, the precondition checks of all its callers might already guarantee that its own pre-condition checks will never be violated. And thus these checks down the chain are unnecessary cpu cycles.
Do there exist tools/methods to detect this and auto-remove these precondition checks?
For example:
the function Muladd below verifies that all arrays have the same length. Muladd relies on two functions to perform the `mul` and the `add` and each of these will also verify their respective preconditions explicitly. Given these functions are not exported and given these functions are only called by `muladd`, the compiler might be able to determine that the precondition checks are guaranteed to be valid and can thus be removed.
package main
import "fmt"
func main() {
x := []float64{1.0, 2.0, 3.0}
y := []float64{1.0, 2.0, 3.0}
z := []float64{1.0, 2.0, 3.0}
Muladd(x, y, z)
fmt.Printf("%+v", x)
}
func Muladd(x []float64, y []float64, z []float64) error {
// check precondition (but unnecessary if only called by Muladd)
if len(x) != len(y) || len(x) != len(z) {
return fmt.Errorf("slices have different lengths %d vs %d vs %d", len(x), len(y), len(z))
}
mul(x, y)
add(x, z)
return nil
}
func mul(x []float64, y []float64) error {
// check precondition
if len(x) != len(y) {
return fmt.Errorf("slices have different lengths %d vs %d", len(x), len(y))
}
for i := range x {
x[i] *= y[i]
}
return nil
}
func add(x []float64, y []float64) error {
// check precondition
if len(x) != len(y) {
return fmt.Errorf("slices have different lengths %d vs %d", len(x), len(y))
}
for i := range x {
x[i] += y[i]
}
return nil
}