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.

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 &* 2

In 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 &+ 1

The 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

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 &+ 1

This 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 + 1

The 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.0

Use normal floating-point arithmetic instead.

let value: Double = 10.5
let result = value + 1.0

The 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 &+ 10

This wraps because UInt8 has a small range.

let larger: UInt16 = 250
let result = larger &+ 10

Here 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 &+ 1

This 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 &+ 1

This 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 &+ 10

The code is clearer because the reason for using &+ is documented.

8. Limitations and Edge Cases

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

11. Practice Exercise

Build a small program that simulates a one-byte score value.

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.