Did you know that constants in Go can't overflow?
Quoting the Go spec:
Numeric constants represent exact values of arbitrary precision and do not overflow. Consequently, there are no constants denoting the IEEE-754 negative zero, infinity, and not-a-number values.
Now this is a very interesting thing about constants in Go, and it’s something that confuses a lot of people. So let’s play around with this one a bit.
If you’re experienced with compiled languages, you’re probably already familiar with numeric overflows. Each language handles this differently, but in general, you can’t store more than 8 bits of data in an 8-bit variable.
var x int8
x += 256
will predictably complain:
256 (untyped int constant) overflows int8
But notice the parenthetical note in that error message: “untyped int constant”
We’ll talk more about untyped constants soon, but for now the interesting thing to point out is that it’s not the constant expression (i.e. 256
) that overflowed. It’s the variable assignment (i.e. x +=
) that overflowed.
This is because, as quoted from the spec above, constants do not overflow.
You can create constant expressions in Go of arbitrary precision, and they’re valid. Check this out:
var x int8
x += 2560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
It still produces essentially the same error:
2560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 (untyped int constant) overflows int8
That value is effectively a 312-bit integer (if my math isn’t off). There’s no data type in Go that can store a 312-bit integer. So you might expect that constant to overflow. But it doesn’t. Because constants do not overflow.
But as soon as you try to assign a constant to a variable, that assignment may cause an overflow.
Jumping ahead a bit to the end of this section in the spec, we see a note on implementation requirements:
Implementation restriction: Although numeric constants have arbitrary precision in the language, a compiler may implement them using an internal representation with limited precision. That said, every implementation must:
- Represent integer constants with at least 256 bits. -Represent floating-point constants, including the parts of a complex constant, with a mantissa of at least 256 bits and a signed binary exponent of at least 16 bits.
- Give an error if unable to represent an integer constant precisely.
- Give an error if unable to represent a floating-point or complex constant due to overflow.
- Round to the nearest representable constant if unable to represent a floating-point or complex constant due to limits on precision.
These requirements apply both to literal constants and to the result of evaluating constant expressions.
So there’s a bit of a caveat to this “constants do not overflow” rule. An implementation may choose to round a constant representations to 256 bits, for example. So my 312-bit example above may be rounded to 2559999999999999972095373170245681839337968901451475214262959301931782193648482834514033246208
in such an implementation (again: if my math isn’t off).
So if you want to be super-paranoid, limit your constant literals to 256 bits of precision. 😉
If you learned something reading this, you'll learn something every day by subscribing to my daily Go mailing list! Sign up for Boldly Go: Daily.
Top comments (6)
Hi Johnathan, is there a reason your title and text mentions constants but your examples are all go variables?
The number 256 is a constant
ITmindCo is correct,
256
is a constant. Or as explained by the spec, it is an "integer literal is a sequence of digits representing an integer constant".I should have been a bit more clear in my explanation.
The number 256 is a hard-coded value being entered into a go variable.
It isn't a const in programming terms, it's just a hard-coded value same as x = x + 1.
By using the word constant you are confusing the readers who understand how go treats consts.
The compiler itself writes that 256 is a constant in the representation of Golang:
256 (untyped int constant)
It is a constant, according to the Go spec, which is what matters in this case, since it is the only sense of "constant" that matters when discussing Go, and it is the sense of constant that cannot overflow.