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 |
|
So, a NASA (or corporate outsourced) programmer came along and wrote:
1 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
We get an error:
1 2 3 4 5 6 7 |
|
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 |
|
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.
-
The Investigation Board report is available at ftp://ftp.hq.nasa.gov/pub/pao/reports/1999/MCO_report.pdf.↩︎
-
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 viewprintln()output.↩︎