Manu rink altconf header

The Secret Life of Types in Swift

An app which uses a results controller, which uses an ORM, which uses SQLite

At first glance, Swift looked different as a language compared to Objective-C because of the modern code syntax. Secondly, the strict and strong type system is also different.

This talk takes an under-the-hood deep dive into the Swift type system’s structure and gives tips how to use it in a proper way.

Introduction

I’m Manu, and I will talk to you about data types today. Swift is pretty simple compared to other languages, and Swift is pretty clear in its architecture of the typing system.

It’s All About Types

There are two things to know first. First, Swift says there shall not be root - $noRoot. And we will never have nil.

An app which uses a results controller, which uses an ORM, which uses SQLite

There’s no specific root type in Swift. For example, in other languages like Java, or C#, or static type systems, they have a root type. Swift does not have a root type, and empty values are not allowed.

In Java, an Integer is just a number. The inheritance line is not long, but we do have two stages of inheritance over the type itself, with interfaces, which conforms to a protocol. Objective-C is similar, as it also conforms to a protocol.

Get more development news like this

An app which uses a results controller, which uses an ORM, which uses SQLite

In Swift, Int is a type of itself, and it defines its data types as structures, not classes.

Dive into Types

In Swift, everything is a structure with no inheritance. The reason this is done is so we can have super loose coupling among each type, and can be extended throughout the whole type system. This allows for clean architecture.

Named Types

An app which uses a results controller, which uses an ORM, which uses SQLite

Named types are types that have names. It’s classes, structures, Enums, and protocols; essentially everything you are giving a name when you are using it.

Compound Types

An app which uses a results controller, which uses an ORM, which uses SQLite

A compound type is a type with no name. The two types of compound types are tuples and functions.

Tuples

	var greatTuple = (x: 10, y: 20)
	greatTuple = (x: 12, y: 50)
	greatTuple = (0,0)
	print (greatTuple.0 + "==" + greatTuple.x) 

This greatTuple variable has exactly the type Int, Int. This is a real type, it just looks like a bit different.

You can attach, or assign a different Int, Int tuple. To do so, leave the parameters, and use the numbers themselves. You can enter the values with the .0, and .1, and so on. Or, you can use the parameter names again.

	greatTuple = (xCoord: 10, yCoord: 20)
	greatTuple = (x: "manu", y: 20)
  

Let’s continue with tuples, and where they are really meaningful.

	func randomColorScheme () -> (fg: UIColor, bg: UIColor) {
		let foreground = randomForegroundColor()
		let background = randomBackgroundColor()

		return (foreground, background)
	}

	let colorScheme = randomColorScheme()
	view.backgroundColor = colorScheme.bg
  

Suppose we want to return more than one value from functions. This is done by just defining the types in the return as a tuple.

Tuple types are unnamed but you can give them a name. With the typealias, you can do exactly this.

	var point = (13, 12)
	
	typealias Point = (Int, Int)
	var myPoint = Point(10, 12)

	typealias Point = (x: Int, y: Int)
	var myPoint = Point(x: 10, y: 12)
	var myPoint = Point(10, 12)
  

Here, we are defining a tuple of just two Ints. There is a variable named Point.

Function Types

Like tuples, functions types are also common.

	func processPerson (withID: Int) -> () {}
	func processVIP (withID: Int) {}
	
	struct Person {
		firstname : String
		lastname : String
	}

	func nameForPerson (withID: Int) -> (name: String, age: Int) {}
	func nameForPerson (withID: Int) -> (Person) {}
	func nameForPerson (withID: Int) -> Person {}
	
	func detailsForPerson (withID: Int) -> (obj: Person, age: Int) {}
  

If I want to return nothing, you can get by with writing nothing. The thing exactly after the name of the function, until the first bracket, is the function type.

Variadic Parameters

A lot of programming languages actually have this.

func printAll(_ numbers: Int...) -> Int {
		for number in numbers {
			print ( "the number \(number)")
		}
	}

I have four parameters for this function, and they are all Int. As soon as you add three dots after the type identifier here, you can use this variable as an array. Treat it like an array and just use it.

Closures

Closures are very similar to blocks in Objective-C with a few differences.


	let names = ["Igor", "Horst", "Manu", "Alex", "David"]
	func ascending (_ s1: String, _s2: String) -> Bool {
		return s1 < s2
	}
	var ascendingNames = names.sorted(by: ascending)

A closure is actually a higher usage of a function type. Above, we just have two types of types; the closure is defined quite similarly to the function itself. This is because it takes the parameters and the area and the return type just as the type signage. This makes functions and closures siblings.

Blocks vs. Closures

An app which uses a results controller, which uses an ORM, which uses SQLite

The syntax of blocks and closures in Objective-C was often difficult for me to remember, this is why I want to show you the following two URLs.

Block Syntax and Closure Syntax

The Sugar On Top

We have sugar on the top in Swift - Optionals. Optionals in Objective-C are not that easy to understand, considering the following definition.

	public enum ImplicitlyUnwrappedOptional<Wrapped> : ExpressibleByNilLiteral {
	
		case none
		
		case some(Wrapped)

		public init (_ some: Wrapped)

		public init(nilLiteral: ())
	}
  

This is just an Enum, which has something in it, or nothing.

With an optional, you can do a lot:

	var myName : Optional<String>
	myName = "manu"
	var theName = "manu"

	if myName != nil && theName != nil {
		print(myName)
		print(theName)
	}
  

An optional is something or nothing, the value that is wrapped in the optional is your “safety net”.

We want to print an optional, and Swift does exactly this. It prints our optional. To forcibly unwrap an optional, you can use a bang operator.

This is done like this.


	var myName : String? = "manu"
	print(myName)
	print(myName!)

	if let name = myName {
		print(name)
	}

If there is no value in the optional, it will fail, and your program will crash.

I recommend to not force unwrap things. Instead, you can do it conditionally, or do the following:


	var name : String? "manu"
	
	guard let myName = name else {
		print("empty name - can't proceed")
		return
	}

	print(myName)
  

We are defining an optional, like before; this is just a string which I give a value to, and only continues after the guard block if myName contains a value.

Next Up: Advanced Swift #10: Everything You Ever Wanted to Know on Sequence & Collection

General link arrow white

About the content

This talk was delivered live in June 2017 at AltConf. The video was recorded, produced, and transcribed by Realm, and is published here with the permission of the conference organizers.

Manu Rink

Manu Rink is a mobile enthusiast long before there was an iPhone. After working for a couple of years in the enterprise business and creating big data visualisations she finally dropped the mic and made her passion to her profession. For the last four years Manu was working as a mobile software engineer and architect and led the development of a couple of #1 App Store apps. Since 2016 she is a technical evangelist @Microsoft and inspires a wide audience of techies for her beloved topics including mobile development, devops and gaming.