The justification is that Swift integer types model the integers, ℤ.
They do not model “integers modulo n”.
• • •
The fact that a fixed-width integer value can only physically represent a subset of the integers is immaterial. The type itself models the whole set.
Thus, an integer which overflows the type is still valid in the model. It just cannot be represented in the limited space available.
• • •
The decision to crash on overflow follows from that design choice. An out-of-range integer is still an integer, and it is still valid in the model. Thus, being unable to represent it is a hard error.
This is why operations like
+ trap on overflow rather than wrap: it represents addition in the integers, not in the integers modulo n.
Similarly, converting from a larger integer type to a smaller one is not a conversion at all in the model, since both types model the integers. If the destination type cannot fit the value, that is an overflow error.
• • •
String can hold values which do not represent integers at all, thus the conversion produces an optional.
The one apparent inconsistency is that strings which do hold an integer, but its value overflows the destination type, produce
nil rather than trapping:
Int8("500") // nil
This can be explained as “attempt to convert the string to a representable value” rather than “attempt to convert the string to an integer, then store the integer”.