go / checked
I use checked arithmetic to detect integer overflow before it causes silent bugs.
The problem
Go's integer arithmetic silently overflows:
var a int64 = math.MaxInt64
b := a + 1 // -9223372036854775808, no error
For financial calculations, counters, or any code where overflow would be a serious bug, you need explicit checks.
The pattern
package checked
import "math"
func AddInt64(a, b int64) (int64, bool) {
if (b > 0 && a > math.MaxInt64-b) ||
(b < 0 && a < math.MinInt64-b) {
return 0, false
}
return a + b, true
}
func SubInt64(a, b int64) (int64, bool) {
if (b > 0 && a < math.MinInt64+b) ||
(b < 0 && a > math.MaxInt64+b) {
return 0, false
}
return a - b, true
}
func MulInt64(a, b int64) (int64, bool) {
if (a > 0 && b > 0 && a > math.MaxInt64/b) ||
(a > 0 && b < 0 && b < math.MinInt64/a) ||
(a < 0 && b > 0 && a < math.MinInt64/b) ||
(a < 0 && b < 0 && b < math.MaxInt64/a) {
return 0, false
}
return a * b, true
}
For unsigned integers, the checks are simpler:
func AddUint64(a, b uint64) (uint64, bool) {
if math.MaxUint64-a < b {
return 0, false
}
return a + b, true
}
func MulUint64(a, b uint64) (uint64, bool) {
if b > 0 && a > math.MaxUint64/b {
return 0, false
}
return a * b, true
}
Usage
total, ok := checked.AddInt64(balance, deposit)
if !ok {
return errors.New("balance overflow")
}
product, ok := checked.MulUint64(price, quantity)
if !ok {
return errors.New("total exceeds maximum")
}
When to use
- Financial calculations (balances, totals, fees)
- Resource accounting (bytes, counts, quotas)
- Anything where overflow would corrupt data or cause security issues
When not to use
- Performance-critical inner loops where overflow is impossible by design
- Hash functions or cryptography that intentionally use wraparound
Alternative: panic variants
If overflow is always a bug and you want to fail fast, use a must pattern:
func MustAddInt64(a, b int64) int64 {
sum, ok := AddInt64(a, b)
if !ok {
panic("integer overflow")
}
return sum
}