Introduction to Swift Types
<!DOCTYPE html> Introduction to Swift Types

Introduction to Swift Types

Let’s Save Half a Billion Dollars

Let’s jump right in by saving half a billion dollars from going to waste.

In 1999 the Mars Climate Orbiter disintegrated upon entering the Martian atmosphere. The orbiter was destroyed because it incorrectly calculated atmosphere insertion distance1.

The calculation causing the failure was extremely simple, and underlying the failure is the basic principle every physics student learns the first week: always include units in your calculations. But, we’re using computers. Somehow, when doing physical calculations with computers, we’re supposed to throw away all units and just write bare numbers everywhere.

Let’s take a step back and fix the MC with Swift.

The original requirement may have looked something like:

1
2
/* TODO: Report forces the orbiter is currently experiencing.
 * Returns impulse in N-s */

So, a NASA (or corporate outsourced) programmer came along and wrote:

1
double smallForces()

Except, their smallForces() function returned American units of foot-pound-second instead of metric units of Newton-second. Nobody caught the error until after the half billion dollar project turned to dust over a red desert.

Using Swift, we can correct their catastrophic error by creating a properly typed returned value. Any other code using the return value will fail to compile if given incorrect types, while also always showing the programmer exactly what the return value means without resorting to reading (or forgetting or overlooking) documentation or specifications.

First, we define our specific return type. In this case, the return type is a momentum in NewtonSecond:

1
2
3
struct NewtonSecond {
    let val: Double
}

In Swift, a struct is a container holding values. The name you give your struct container is the name of your type. Here, we’re creating a named type NewtonSecond holding only one inner value: the very blandly named val element of type Double.

With our type now defined, we can create an infallible smallForces() function (infallible as far as types are concerned):

1
2
3
func smallForces() -> NewtonSecond {
    return NewtonSecond(val: 1200)
}

The output of smallForces() is returned as a NewtonSecond struct, as denoted by the -> NewtonSecond portion of the function declaration.

Also notice how we create a new NewtonSecond: we call the type as a function. Swift gives us, for free, behind-the-scenes initialization methods for struct types. All you have to do is define the properties of your struct along with their data types, and Swift creates an initialization method accepting all properties or you.

Let’s define another, competing, struct for American units called FootPoundSecond:

1
2
3
struct FootPoundSecond {
    let val: Double
}

The new container has the same inner definition as our NewtonSecond, but it has a unique name.

Let’s get the current smallForces() value and use the reading to updateNavigation():

1
2
3
4
5
6
7
8
var currentForce = smallForces()

func updateNavigation(forces: NewtonSecond) {
    /* update entire orbiter navigation here */
    println("Updated navigation using NewtonSecond units")
}

updateNavigation(currentForce)

Everything works great2. We read a value of type NewtonSecond then gave the value to updateNavigation() and it ran with zero errors.

What happens if we pass a type of FootPoundSecond to updateNavigation()? Both types have the exact same inner properties after all. The two types only differ in their naming.

1
updateNavigation(FootPoundSecond(val: 300))

We get an error:

1
2
3
4
5
6
7
Playground execution failed: error: <REPL>:23:18: error: 'FootPoundSecond' is
not convertible to 'NewtonSecond'

updateNavigation(FootPoundSecond(val: 300))
                 ^
<REPL>:17:23: note: in initialization of parameter 'forces'
func updateNavigation(forces: NewtonSecond) {

Swift detected we tried to pass a FootPoundSecond type to a NewtonSecond parameter and failed to compile.

What if we really wanted to work in units of FootPoundSecond though? Will Swift let us define the same function name again, but with a different parameter type?

1
2
3
4
5
6
func updateNavigation(forces: FootPoundSecond) {
    /* update entire oribiter navigation here */
    println("Updated navigation using FootPoundSecond units")
}

updateNavigation(FootPoundSecond(val: 900))

Now, if you have your REPL window labeled “Console Output” showing, you’ll see when we pass units of FootPoundSecond to updateNavigation(), Swift calls the correct function matching our input type.

This is the first time a modern Cocoa development environment has had access to a common type-aware language.

And that is all they had to do to not blow up a $622 million spacecraft.

Addendum

Thinking about programming types as physical units can help drive the point home.

You can’t convert distance to weight (500 km == ? kg), but the historical usage of built-in programming types everywhere (string, int, float) has broken the average programmer’s ability to think about types and units.

It’s perfectly acceptable to the compiler if you pass in 5 to a function named timeUntilWorldEnds, but what if it turns out you were distracted, and the 5 you typed represented five dollars you wanted to spend for lunch and not five seconds until the end of the world?

Let the compiler help you prevent catastrophic failures.

Let the compiler make you awesome.


  1. The Investigation Board report is available at ftp://ftp.hq.nasa.gov/pub/pao/reports/1999/MCO_report.pdf.

  2. println() output goes to the Playground console, not to your local REPL output, so you’ll have to open the REPL console, which isn’t the same as the regular Xcode output console, to view println() output.