Swift Overflow Operators (&+, &-, &*) Explained Clearly
Swift’s overflow operators let integer arithmetic continue past a type’s normal limits instead of stopping with a runtime trap. In this article, you will learn what &+, &-, and &* do, why Swift provides them, how wraparound arithmetic works, and when these operators are useful in real code.
1. What Is Overflow Operators (&+, &-, &*)?
Overflow operators are special arithmetic operators for integer types in Swift. They behave like normal addition, subtraction, and multiplication, except they allow values to wrap around when the result goes beyond the representable range of the type.
For example, a UInt8 value can store numbers from 0 to 255. If you add 1 to 255 using normal +, Swift traps at runtime. If you use &+, the result wraps back to 0.
- &+ performs overflow addition.
- &- performs overflow subtraction.
- &* performs overflow multiplication.
- They work with Swift integer types such as Int, UInt, Int8, and UInt64.
- They do not prevent overflow; they intentionally allow wraparound behavior.
- They are most useful when wraparound arithmetic is the desired result.
2. Why Overflow Operators Matters
Normal arithmetic in Swift is designed to be safe. If a calculation goes beyond what a type can represent, Swift stops the program rather than silently producing a wrong value. That is usually the correct choice.
However, some algorithms need arithmetic that wraps around at the type boundary. This is common in low-level programming, bit manipulation, checksums, hashing, random number generation, counters, and code that mirrors hardware or protocol behavior.
You should use overflow operators when wraparound is intentional and expected. You should not use them as a shortcut to avoid handling number range problems in ordinary business logic.
Warning: Overflow operators are not a safer version of normal arithmetic. They are a deliberate choice to get wraparound results.
3. Basic Syntax or Core Idea
Using the operators
The syntax looks almost the same as normal arithmetic, but each operator starts with &. The following example shows all three operators with fixed-width integer types so the wraparound is easy to see.
let maxValue: UInt8 = 255
let wrappedAdd = maxValue &+ 1
let minValue: UInt8 = 0
let wrappedSubtract = minValue &- 1
let product: UInt8 = 200
let wrappedMultiply = product &* 2In this code, wrappedAdd becomes 0, wrappedSubtract becomes 255, and wrappedMultiply wraps to the low 8 bits of the mathematical result.
Why wraparound happens
Swift integer types have fixed storage sizes. A UInt8 stores exactly 8 bits. Once a calculation goes beyond those 8 bits, overflow operators keep only the bits that fit. That is why the result appears to cycle through the valid range.
This behavior is sometimes called modular arithmetic. For UInt8, values wrap modulo 256.
Normal arithmetic versus overflow arithmetic
The next example shows the conceptual difference between the standard operators and overflow operators.
let value: UInt8 = 255
// value + 1 would trap at runtime
let wrapped = value &+ 1The important idea is simple: use normal operators when overflow should be treated as a bug, and use overflow operators when wraparound is the intended outcome.
4. Step-by-Step Examples
Example 1: Wrapping at the top of an unsigned range
This example shows a UInt8 moving past its maximum value.
let highest: UInt8 = 255
let next = highest &+ 1
print(next)The printed result is 0. This is the simplest form of wraparound arithmetic.
Example 2: Wrapping below zero with unsigned integers
Unsigned types cannot represent negative numbers. With normal subtraction, going below zero would trap. With &-, the result wraps to the top of the range.
let start: UInt8 = 0
let previous = start &- 1
print(previous)The result is 255. This is useful for cyclic counters or byte-based operations.
Example 3: Overflow multiplication with a small integer type
Multiplication can overflow quickly with small fixed-width types. This example makes that visible.
let a: UInt8 = 200
let b: UInt8 = 2
let result = a &* b
print(result)The mathematical result is 400, but UInt8 can only store up to 255. The value wraps and the stored result is 144.
Example 4: Signed integer wraparound
Overflow operators also work with signed integers. Here, adding past the maximum signed value wraps to the minimum signed value.
let largest: Int8 = 127
let wrapped = largest &+ 1
print(wrapped)The result is -128. Signed integers use two’s-complement representation, so the wraparound follows that bit pattern.
5. Practical Use Cases
- Implementing cyclic counters that should restart automatically after reaching a maximum value.
- Working with raw bytes in binary formats, network protocols, or file parsers.
- Building hash functions or checksum logic where modular arithmetic is part of the algorithm.
- Writing pseudo-random number generators that depend on fixed-width integer wraparound.
- Mirroring low-level hardware behavior where arithmetic is naturally limited by register size.
- Performing bit-level transformations where the wrapped result is expected and meaningful.
6. Common Mistakes
Mistake 1: Using overflow operators when normal arithmetic is actually needed
Some developers use overflow operators just to avoid runtime traps, but that often hides a logic bug.
Warning: Bad pattern: wraparound used to ignore invalid numeric growth.
let cartItemCount: UInt8 = 255
let newCount = cartItemCount &+ 1This wraps to 0, which is clearly wrong for a shopping cart count.
Use a larger type or validate the operation instead.
let cartItemCount: Int = 255
let newCount = cartItemCount + 1The corrected version uses a more appropriate type and standard arithmetic.
Mistake 2: Expecting overflow operators to work with floating-point values
Overflow operators are for integer arithmetic, not floating-point types like Double or Float.
Warning: Bad pattern: using overflow operators with non-integer types.
// This does not compile
let value: Double = 10.5
// let result = value &+ 1.0Use normal floating-point arithmetic instead.
let value: Double = 10.5
let result = value + 1.0The corrected code uses the standard operator because floating-point types follow different numeric rules.
Mistake 3: Forgetting that type size changes the result
The same arithmetic can produce different wrapped results depending on whether you use UInt8, UInt16, or UInt32.
Warning: Bad pattern: assuming all integer types wrap the same way.
let small: UInt8 = 250
let wrapped = small &+ 10This wraps because UInt8 has a small range.
let larger: UInt16 = 250
let result = larger &+ 10Here the result is simply 260 because UInt16 has room for that value.
7. Best Practices
Practice 1: Use overflow operators only when wraparound is part of the design
Make your intent explicit. If the algorithm depends on modular arithmetic, overflow operators communicate that clearly to readers.
var byte: UInt8 = 255
byte = byte &+ 1This is appropriate because wrapping from 255 to 0 is intentional.
Practice 2: Prefer fixed-width integer types when exact overflow behavior matters
If you rely on exact bit width, use types like UInt8, UInt32, or Int16 instead of platform-sized types when consistency is important.
let seed: UInt32 = 4_294_967_295
let nextSeed = seed &+ 1This always wraps the same way because UInt32 has a known width.
Practice 3: Add comments when the wraparound may not be obvious
Overflow arithmetic can surprise readers who expect normal safety checks. A short comment helps explain why it is correct here.
let checksum: UInt8 = 250
// Wraparound is intentional because the protocol uses byte-sized modular arithmetic.
let updatedChecksum = checksum &+ 10The code is clearer because the reason for using &+ is documented.
8. Limitations and Edge Cases
- Overflow operators apply to integer types, not floating-point numbers.
- The wrapped result depends on the type’s bit width. A calculation on UInt8 may wrap while the same one on UInt64 may not.
- Int and UInt are platform-sized types, so their exact range depends on the target architecture.
- Signed wraparound can be harder to reason about than unsigned wraparound because negative values are represented using two’s complement.
- Overflow operators do not report whether overflow happened. They only give the wrapped result.
- If you need both the result and an overflow flag, methods such as addingReportingOverflow(_:), subtractingReportingOverflow(_:), and multipliedReportingOverflow(by:) may be a better fit.
Overflow operators are useful, but if you need to detect overflow instead of silently wrapping, the reporting APIs are often the better tool.
9. Practical Mini Project
Let’s build a tiny byte counter that simulates a one-byte device register. A one-byte register can store values from 0 to 255. Incrementing past the maximum should wrap back to 0.
struct ByteCounter {
private(set) var value: UInt8 = 0
mutating func increment() {
value = value &+ 1
}
mutating func decrement() {
value = value &- 1
}
}
var counter = ByteCounter()
for _ in 1...3 {
counter.decrement()
print(counter.value)
}
counter = ByteCounter()
for _ in 1...257 {
counter.increment()
}
print(counter.value)This small project demonstrates both directions of wraparound. Starting from 0, decrementing three times produces 255, 254, and 253. Then incrementing 257 times wraps once and ends at 1.
The example is simple, but it models real situations where storage size is fixed and cyclic arithmetic is expected.
10. Key Points
- &+, &-, and &* are Swift’s integer overflow operators.
- They allow arithmetic to wrap around instead of trapping at runtime.
- They are useful when modular arithmetic is intentional, such as byte processing or low-level algorithms.
- The wrapped result depends on the specific integer type and its bit width.
- They should not be used to hide ordinary numeric bugs in application logic.
- If you need to know whether overflow occurred, use the reporting overflow methods instead.
11. Practice Exercise
Build a small program that simulates a one-byte score value.
- Create a UInt8 variable named score starting at 254.
- Add 3 using an overflow operator.
- Subtract 5 using an overflow operator.
- Print the intermediate and final results.
Expected output: the value should wrap during addition and still produce a valid UInt8 result after subtraction.
Hint: Start with 254, then apply &+ 3, then &- 5.
var score: UInt8 = 254
score = score &+ 3
print("After adding 3: \(score)")
score = score &- 5
print("After subtracting 5: \(score)")This solution first wraps 254 forward by three steps, giving 1. It then subtracts five with wraparound, producing 252.
12. Final Summary
Swift overflow operators give you explicit control over wraparound arithmetic for integers. Instead of trapping when a value goes beyond the range of its type, &+, &-, and &* keep the calculation within the type’s fixed bit width and return the wrapped result.
That behavior is powerful when it matches the problem you are solving, especially in byte manipulation, hashing, cyclic counters, and low-level data processing. It is not a replacement for normal arithmetic safety, though. In most app code, standard operators are still the better choice because they expose range errors instead of hiding them.
A good next step is to learn Swift’s overflow-reporting methods so you can compare intentional wraparound with arithmetic that also tells you whether an overflow occurred.