Why Type-Safety is Essential in Swift

What’s worse than crashing? Not crashing!

Image for post
Image for post
Photo by Leighann Blackwood on Unsplash

How can a program that crashes be better than a program that doesn’t crash.

This article explains what type safety means for Swift, and why that statement isn’t as crazy as it seems.

Difficulty: Beginner | Easy | Normal | Challenging (although the work on pointers later in the article can be tricky to understand)

Prerequisites:

  • Coding in Swift Playgrounds (guide HERE)

Terminology

Regarding type safety

Compiler: A program that converts instructions into a machine-code or lower-level form so that they can be read and executed by a computer

Type safety: The extent to which a programming language prevents type errors

Regarding Pointers (later in the article)

Pointer: An object that stores a memory address

UnsafePointer: A pointer for accessing data of a specific type

UnsafeRawPointer: A raw pointer for accessing untyped data. This means there is no type safety and no alignment

Type safety

We can think of type safety in programming as:

  1. Blocking the ability to read from uninitialized variables
  2. Arrays cannot be accessed beyond their bounds
  3. Unchecked type casts are not possible

Example: an uninitialised variable

Swift will catch us if we try to use a variable before it’s initialized; even (in the case of the example below) there is a chance it can’t be initialized.

Image for post
Image for post

Thanks Swift.

Example: Int and String

If you want to store a variable as a String, the fact that Swift is type-safe prevents you from passing an Integer (or any other type) to that variable.

let myStr: String = “Hello”
let strErr: String = 4 // error
Image for post
Image for post

This happens at compile time, and means that an end-user should never see such an error (which is great!)

Example: Optionals

Optionals are subject to the same type-safety; we can’t use an optional that requires a non-optional type.

let myStr: String? = “Hello”
var str: String = myStr // error
Image for post
Image for post

Even though the Swift compiler comes up with nots of nice solutions for us to solve the problem, it is still an error and once again stops us making a silly slip with our types!

Nice!

Example: Force Unwrapping

It always seems unfortunate that a runtime crash can be caused by force-unwrapping an optional in Swift.

When we force-unwrap we equivalently say to the Swift compiler “I’ve got this — the variable or constant will never be nil”.

The compiler does not check this since it can’t know if the optional is nil; it might be dependent on user input or a random number so force unwrapping means that the compiler never checks.

let myStr: String? = nil
print(myStr!)
Image for post
Image for post

However Swift is still type-safe since the behaviour is defined.

Example: Reading outside the bounds of an Array

In C, by design, reading outside an array’s bounds is undefined (Since C favors performance over safety — this is why many OS’s run fast). In Swift, our type-safe language, this is not true. This means that the following gives an error at runtime:

let names = [“Paven”,”Kim”,”Dave”]
names[3] // error
Image for post
Image for post

The error given (EXC_BAD_INSTRUCTION) is a defined behaviour, which means we can’t access elements from outside the array.

The advantage of type safety

Your end user should never see such errors, they should be caught by the programmer. That is, the error should be caught in advance of even a (theoretical) tester being exposed to your work.

This is a Bingo, since the error is caught so early in the development process that the programmer can fix a slip before anyone else is even aware of it; that is it is so early in the process.

What if we weren’t in a type safe world

You can move into a world that is not type-safe, even in Swift.

One way to approach this is with pointers, where we can actually rebind memory to a different type and no type checking takes place.

We take a String (“Paven”) and create a pointer to that instance (using an UnsafePointer to do so). We can then bind this to a different type!

On my machine namePointer points to memory location 0x0000000124c21140 and the String will be at that location.

Strings are stored by Swift’s Unicode Scalar Values which is a 21-bit number. However as asciiA is equivalent to 65 in denary. Swift’s String type is said to be built from Unicode Scalar Values. In Swift this is a 21-bit number (All this is covered in another article).

This pointer is cast to another type — this type is from String to Integer.

Both the original pointer and the intPointer refer to the same location; but we are interpreting the bytes at that point as an Integer rather than a String.

We can even see the elements from the bytes by using the following code:

Which is a representation of UnsafeRawBufferPointer(start: 0x00000001228ed140, count: 16) and returns the following bytes:

Image for post
Image for post

Which makes sense as, surprise surprise, the ASCII code for A is 65. Please do note that short strings are stored directly at a Pointer, but longer strings may not be (and since String is a struct, this is why 65 is at the first location in the array as this is not a simple representation of the ASCII code).

As you can see, an unchecked type cast has just been performed! If the types are different sizes we are just asking for trouble as we could be reading…which memory location again?

Conclusion

Type safety is really important since it means we have defined behaviour for operations. This allows us to have a safe language, not just for making sure that types are (in some respect) correct but stops various vectors of attack (like accessing outside the bounds of an array).

We can even go so far as to use pointers, perhaps even unsafePointers to sidestep Swift’s type safety if we so choose.

I hope this tutorial has given you some idea of what this means, and some feeling of under the working under the hood of Swift.

The Twitter contact:

Any questions? You can get in touch with me HERE

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store