tezvyn:

Default integer overflow behavior in Go versus Rust

AI-drafted, machine-checkedSource: doc.rust-lang.orgadvanced
WHAT IT TESTS

Go silent wrapping vs Rust mode-based defaults.

ANSWER OUTLINE

Go wraps silently; Rust panics in debug, wraps in release; Rust has wrapping_, checked_, saturating_ methods; Go needs manual checks.

RED FLAG

Saying Go panics or Rust never wraps.

WHAT THIS TESTS: This question probes whether you understand the fundamental safety philosophy gap between Go and Rust at the language-runtime boundary. It checks if you know that Rust makes overflow behavior explicit and mode-dependent while Go leaves it silent, and whether you can name the specific APIs and idioms each community uses to mitigate the risk. Senior candidates should connect this to production concerns like debuggability, performance, and defensive coding.

A GOOD ANSWER COVERS: First, state that Go uses two's complement arithmetic and silently wraps on every integer overflow for both signed and unsigned types; there is no built-in panic or trap. Second, explain that Rust distinguishes debug from release builds: in debug mode the compiler inserts runtime checks that panic on overflow, while in release mode it wraps exactly like Go. Third, for Rust, list the explicit method families that override the default: wrapping_add and siblings for modular arithmetic, checked_add which returns Option, saturating_add which clamps to the type bounds, and overflowing_add which returns a tuple of value and overflow flag. Fourth, for Go, explain that the language has no standard checked arithmetic, so the common practice is manual bounds checking before an operation or using the math/bits package to detect carries and overflows explicitly. Fifth, mention that Rust also allows crate-level control via the overflow-checks compiler flag, though methods are preferred.

COMMON WRONG ANSWERS: A major red flag is asserting that Go panics on integer overflow; it never does for standard fixed-width integer types. Another is stating that Rust always panics on overflow, which ignores the release-mode wrapping default. Candidates also err by saying Rust has no way to opt out of panics in debug mode; in fact the wrapping_ family works in any mode. In the Go portion, suggesting that big.Int is the common fix is misleading; it solves arbitrary precision but is not the standard mitigation for fixed-width overflow. Finally, confusing floating-point NaN or infinity behavior with integer overflow shows a weak grasp of numeric semantics.

LIKELY FOLLOW-UPS: An interviewer might ask when you would actually want wrapping semantics in Rust, so be ready to discuss hash functions, checksums, and cryptography where modular arithmetic is correct by design. They might also ask how you would build a safe saturating add in Go, which forces you to reason about MaxInt and MinInt pre-conditions manually. Another angle is the performance cost of Rust's debug checks and why they are disabled in release; you should know that the branch instructions can inhibit vectorization and add overhead. A systems-level follow-up could compare this with C or C++ undefined behavior on signed overflow.

ONE CONCRETE EXAMPLE: Imagine a request-rate counter in a load balancer written in Go. If the counter is a uint64 and traffic spikes cause it to increment past the max value, it silently wraps to zero and the metrics become garbage. The typical Go defense is to check if rate == math.MaxUint64 before incrementing, or to use bits.Add64 and inspect the carry return value. In Rust, the same service might use a checked_add in a tight loop, returning None when the limit is reached so the caller can saturate or log, while a hash-computation routine in the same codebase would use wrapping_mul to guarantee deterministic output without paying for debug-only panics.

Read the original → doc.rust-lang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.