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.↩