I was at Jesse Squires’s talk at iOS Conf Singapore, where he discussed Swift’s numeric types and protocols. That reminded me of SE-0104, Protocol-oriented integers and now that the implementation is in Swift 4, thought it would be a good time to have a closer look.

Let’s start with the protocol hierarchy for `Int`

, everyone’s favorite integer type:

As with most types in the standard library, `Int`

conforms to a whole lot of protocols! All the way down the chain, `Numeric`

is one of the base protocols. All the different sized integer types (`UInt`

, `Int8`

, etc.) as well as floating-point types (`Float`

, `Double`

, etc.) conform to `Numeric`

.

## Numeric, Starting From 0x00

You can follow along with the standard library source in Integers.swift.gyb, although as usual, all the relevant code will be inline below.

Here’s the protocol declaration to start:

```
public protocol Numeric : Equatable, ExpressibleByIntegerLiteral {
```

Two additional conformances here:

`Equatable`

adds support for the`==`

operator.`ExpressibleByIntegerLiteral`

allows for code like`let a: Int = 42`

where`42`

is the aforementioned “integer literal”.

That means all numeric types can be initialized with integer literals but not float literals. This bit of code is OK:

```
let someFloat: Float = 42 // ✅
```

But this is not OK:

```
let someInt: Int = 4.2 // 🙅
```

You’ll run into the `ExpressibleByFloatLiteral`

protocol in specific floating-point types, but not at the level of general `Numeric`

types.

## Initialization

The protocol has one required initializer:

```
init?<T : BinaryInteger>(exactly source: T)
```

It’s a failable initializer, and the “exactly” in the argument label should tell you why: if you try to initialize an instance with a value beyond what it can hold, the initializer will return `nil`

:

```
let ok = Int8(exactly: 10) // 10
let tooBig = Int8(exactly: 300) // nil
```

Also note the constraint on the source type: it has to conform to `BinaryInteger`

. `BinaryInteger`

conforms to `Numeric`

so it seems a little weird for a “parent” protocol like `Numeric`

to need a type that conforms to a “child” protocol like `BinaryInteger`

to construct itself. What’s going on here?

### Representation vs Use

A quick sidebar on exactly what these two protocols `BinaryInteger`

and `Numeric`

are for.

According to the header docs, `BinaryInteger`

is just what it says on the tin: “An integer type with a binary representation”. That’s pretty familiar to many programmers as we use integers measured in bits all the time.

`Numeric`

, on the other hand, isn’t so much about representation as it is about *usage*. The protocol “provides a suitable basis for arithmetic on scalar values”.

OK, back to arithmetic then. 🤓

## Magnitude

Magnitude is the absolute value of the number, so `42.magnitude`

and `-42.magnitude`

are both `42`

.

```
associatedtype Magnitude : Comparable, Numeric
var magnitude: Magnitude { get }
```

The `magnitude`

computed property has to be `Numeric`

and also `Comparable`

. That means a number itself doesn’t have to be comparable, but its magnitude does.

When you look at the concrete implementation of types such as `Int`

, you’ll see it uses `magnitude`

to do some arithmetic, calculate distance between numbers, etc.

## Arithmetic

We’ve reached our favorite arithmetic operation: addition!

```
static func + (_ lhs: Self, _ rhs: Self) -> Self
static func +=(_ lhs: inout Self, rhs: Self)
```

The first addition function takes two values and produces the sum; the second is the *mutating* version where the “left hand side” argument (the `a`

in `a += 10`

) is mutated.

In your own numeric types, you should at a minimum provide the implementation for the mutating operators.

If you’ve coded types that conform to `Equatable`

, you’ll remember you need to provide an implementation for `==`

and then you get `!=`

for free.

Similarly, the usual pattern is to define `+`

in terms of `+=`

. For example, the implementaton of `+`

in the concrete standard library type `UInt16`

uses `+=`

:

```
// Inside the UInt16 implementation
public static func +(_ lhs: UInt16, _ rhs: UInt16) -> UInt16 {
var lhs = lhs
lhs += rhs
return lhs
}
```

Finally, the `Numeric`

protocol also requires operators for subtraction and multiplication:

```
static func - (_ lhs: Self, _ rhs: Self) -> Self
static func -=(_ lhs: inout Self, rhs: Self)
static func * (_ lhs: Self, _ rhs: Self) -> Self
static func *=(_ lhs: inout Self, rhs: Self)
```

Same guidelines apply, where you should provide the mutating version for your own conforming types.

## Things Left Unsaid

Concrete numeric types do much more than what’s defined here in this one protocol. As you saw from the diagram at the top of this post, there are a lot of protocols put together to make something as complex as a Swift integer.

That said, we’ve only covered `Numeric`

and seen just a slice of all the functionality we’re used to from a numeric type. What are some of the big things missing?

**Division**— we’ve seen addition, subtraction, and multiplication, but what of the missing arithmetic family member? Division is defined separately in the`BinaryInteger`

and`FloatingPoint`

protocols.The function definitions in the protocols are the same, but the specs are slightly different: integer division discards the remainder, and floating-point division follows the IEEE-754 rules.

**Floating-point things**— you saw how types that conform to`Numeric`

are also`ExpressibleByIntegerLiteral`

but not expressible by float literals. Integers can be converted to floats in a straightforward manner, but you need to consider rounding when going from float to integer. How should this rounding work? That’s something out of scope for`Numeric`

.**Comparable**— again, this is something found on the`BinaryInteger`

and`FloatingPoint`

protocol level, except for the`magnitude`

property you saw earlier. Both those protocols conform to`Strideable`

, which in turn implies`Comparable`

.

## The Closing Brace

The `Numeric`

protocol provides the fundamentals of numeric types:

- Initialization with integer values
- Equatable
- Simple arithmetic
- The concept of a
*magnitude*to determine its underlying value

In addition to the missing things listed in the previous section, the protocol also has no opinion on *storage*. Remember, `Numeric`

is about what numbers are *used* for, while the other protocols down the line such as `BinaryInteger`

are about *representation* and how the values are stored.

Ready to build your own custom vigesimal numeric type yet? 😉

`}`