Swift Integer Overflow issue

Recently I had this conversation on bugreport.apple.com with Apple engineer. I filled report that application will crash when initialized with bigger value than can be stored in initialized object, as a respond

“determined that this issue behaves as intended. UInt8(u) is a checked conversion. 773162 is not representable as an 8-bit unsigned integer, so it traps.”.

Well.. I disagree. I think that code should not crash in runtime if there are situations where size of type overflow (in bits right?) is obvious. It should not compile, or this should be not possible at all.

Situation looks like this:

let big:UInt64 = 576460752303423504
let small:UInt8 = UInt8(big) // crash

because integer value 576460752303423504 need more than 8 bits to represent value and Swift (by design) do not truncate bits (that’s fine). The cause is:

init(_ v: UInt64)

for a sake, why UInt8 have this initializer at all? it potentially crash app. Situation is grotesque when I think about Int type. I know that Int is 32 or 64 bit wide. So this example

let a:Int = 576460752303423504

will or will not crash depends on device it’s run on (iPhone5 is 32-bit, iPhone 5s is 64-bit). Why the hell I would allow this? I don’t want actually… but I can.

I stand on a position that if programmer need to cast to smaller type it should be done by programmer like this:

 let truncated = UInt8(576460752303423504 & 0xFF) // truncate bits intentionally. Size of AND operation is clear (1 byte) so no crash. No crash, no problem.
IntMax to the rescue

Generally it is good idea always operate with values as wide as possible (UIntMax, IntMax). IntMax is currently defined as Int64 so it’s wide enough. Of course. if I’m on 32-bit device is not so good idea because my Int is 32-bit, my IntMax is 64-bit so there may be case where I initialize my Int value and that will be overflow (ouch).

Working with generic values is possible thanks to protocol SignedIntegerType/UnsignedIntegerType where I found handy function “from”

class func from(_: IntMax) -> Self

very usable. It is implemented by all Int based structs so after value is cast to IntMax, result can be used to initialize Generic type in safe manner

let result = T.from(IntMax(1)) // T: SignedIntegerType

Just to mention about this protocol. Overflow safe functions that language designers gave us. Very handy. Crash sometimes. Allows do basic math with overflow in scope.

let result = UInt8.addWithOverflow(255, 2) // = 1, true

is equivalent of this

let result = (255 as UInt8) &+ 2 // 1

but with information about overflow.

Update for Xcode 6.1 beta

Issue has been somehow addressed in Xcode 6.1 beta with truncatingBitPattern initializers, like this one for UInt8:

init(truncatingBitPattern: UInt16)

Construct a Int8 having the same bitwise representation as the least significant bits of the provided bit pattern.