Swift does not do implicit type conversions between integers of different sizes and signages. By contrast, Java does implicit conversion, but with less risk of unexpected effects due to the lack of unsigned integer types. C, that dinosaur, has a strange and secret show behind every elementary school math operation.

Why is type conversion confusing? I’ll use C as my example. CERT has some of the best low-level down-and-dirty descriptions of the language, so I’ll be borrowing heavily from their examples.

We’ll start with an easy one: Promotion. During arithmetic, everything is automatically promoted up to int or uint (32 bits on most platforms) in order to prevent overflow. It is curious that they don’t promote to something bigger (long), but x86 assembly uses 32-bit registers most of the time, so it’s a natural fit.

If we run this in the debugger, using the lldb command type format add –format “unsigned dec” “unsigned char” for clarity, we see the following:

(lldb) frame variable

(unsigned char) appleCharOp1 = 80

(unsigned char) appleCharOp2 = 70

(unsigned char) appleCharOp3 = 100

(unsigned char) appleCharResult = 56

(unsigned char) appleCharWrongResult = 2

The correct answer is the result of being able to hold the intermediate product, 5600, in a 32-bit variable. If you truncate the intermediate product to 8 bits, you get 0xE0, which is 224. Divide this by 2 gives you 2 after rounding.

Mind you, the end result is that you get the expected answer as long as you don’t stick a weird cast in the middle like I did there. But here is an example where you get the wrong answer without any extra work: