There is an updated edition of this book available! View Latest Edition
Home iOS & Swift Books Swift Apprentice

2
Types & Operations Written by Matt Galloway

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Now that you know how to perform basic operations and manipulate data using these operations, it’s time to learn more about types. Formally, a type describes a set of values and the operations that can be performed on them. In this chapter, you’ll learn about handling different types, including strings which allow you to represent text. You’ll learn about converting between types and you’ll also be introduced to type inference which makes your life as a programmer a lot simpler. Finally, you’ll learn about tuples which allow you to make your own types made up of multiple values of any type.

Type conversion

Sometimes you’ll have data in one format and need to convert it to another. The naïve way to attempt this would be like so:

var integer: Int = 100
var decimal: Double = 12.5
integer = decimal

Swift will complain if you try to do this and spit out an error on the third line:

Cannot assign value of type 'Double' to type 'Int'

Some programming languages aren’t as strict and will perform conversions like this silently. Experience shows this kind of silent, automatic conversion is a source of software bugs and often hurts performance. Swift disallows you from assigning a value of one type to another and avoids these issues.

Remember, computers rely on us programmers to tell them what to do. In Swift, that includes being explicit about type conversions. If you want the conversion to happen, you have to say so!

Instead of simply assigning, you need to explicitly say that you want to convert the type. You do it like so:

integer = Int(decimal)

The assignment on the third line now tells Swift unequivocally that you want to convert from the original type, Double, to the new type, Int.

Note: In this case, assigning the decimal value to the integer results in a loss of precision: The integer variable ends up with the value 12 instead of 12.5. This is why it’s important to be explicit. Swift wants to make sure you know what you’re doing and that you may end up losing data by performing the type conversion.

Operators with mixed types

So far, you’ve only seen operators acting independently on integers or doubles. But what if you have an integer that you want to multiply by a double?

let hourlyRate: Double = 19.5
let hoursWorked: Int = 10
let totalCost: Double = hourlyRate * hoursWorked
let totalCost: Double = hourlyRate * Double(hoursWorked)

Type inference

Up to this point in this book, each time you’ve seen a variable or constant declared it’s been accompanied by a type annotation. You may be asking yourself why you need to bother writing the : Int and : Double, since the right hand side of the assignment is already an Int or a Double. It’s redundant, to be sure; your crazy-clever brain can see this without too much work.

let typeInferredInt = 42

let typeInferredDouble = 3.14159

let wantADouble = 3
let actuallyDouble = Double(3)
let actuallyDouble: Double = 3
let actuallyDouble = 3 as Double

Mini-exercises

  1. Create a constant called age1 and set it equal to 42. Create a constant called age2 and set it equal to 21. Check using Option-click that the type for both has been inferred correctly as Int.
  2. Create a constant called avg1 and set it equal to the average of age1 and age2 using the naïve operation (age1 + age2) / 2. Use Option-click to check the type and check the result of avg1. Why is it wrong?
  3. Correct the mistake in the above exercise by converting age1 and age2 to type Double in the formula. Use Option-click to check the type and check the result of avg1. Why is it now correct?

Strings

Numbers are essential in programming, but they aren’t the only type of data you need to work with in your apps. Text is also an extremely common data type, such as people’s names, their addresses, or even the words of a book. All of these are examples of text that an app might need to handle.

How computers represent strings

Computers think of strings as a collection of individual characters. In Chapter 1 of this book, you learned that numbers are the language of CPUs, and all code, in whatever programming language, can be reduced to raw numbers. Strings are no different!

Unicode

In isolation, a computer is free to choose whatever character set mapping it likes. If the computer wants the letter a to equal the number 10, then so be it. But when computers start talking to each other, they need to use a common character set.

Strings in Swift

Swift, like any good programming language, can work directly with characters and strings. It does so through the data types Character and String, respectively. In this section, you’ll learn about these data types and how to work with them.

Characters and strings

The Character data type can store a single character. For example:

let characterA: Character = "a"
let characterDog: Character = "🐶"
let stringDog: String = "Dog"
let stringDog = "Dog" // Inferred to be of type String

Concatenation

You can do much more than create simple strings. Sometimes you need to manipulate a string, and one common way to do so is to combine it with another string.

var message = "Hello" + " my name is "
let name = "Matt"
message += name // "Hello my name is Matt"
let exclamationMark: Character = "!"
message += String(exclamationMark) // "Hello my name is Matt!"

Interpolation

You can also build up a string by using interpolation, which is a special Swift syntax that lets you build a string in a way that’s easy to read:

message = "Hello my name is \(name)!" // "Hello my name is Matt!"
let oneThird = 1.0 / 3.0
let oneThirdLongString = "One third is \(oneThird) as a decimal."

Multi-line strings

Swift has a neat way to express strings that contain multiple lines. This can be rather useful when you need to put a very long string in your code.

let bigString = """
  You can have a string
  that contains multiple
  lines
  by
  doing this.
  """
print(bigString)
You can have a string
that contains multiple
lines
by
doing this.

Mini-exercises

  1. Create a string constant called firstName and initialize it to your first name. Also create a string constant called lastName and initialize it to your last name.
  2. Create a string constant called fullName by adding the firstName and lastName constants together, separated by a space.
  3. Using interpolation, create a string constant called myDetails that uses the fullName constant to create a string introducing yourself. For example, my string would read: "Hello, my name is Matt Galloway.".

Tuples

Sometimes data comes in pairs or triplets. An example of this is a pair of (x, y) coordinates on a 2D grid. Similarly, a set of coordinates on a 3D grid is comprised of an x-value, a y-value and a z-value. In Swift, you can represent such related data in a very simple way through the use of a tuple.

let coordinates: (Int, Int) = (2, 3)
let coordinates = (2, 3)
let coordinatesDoubles = (2.1, 3.5)
// Inferred to be of type (Double, Double)
let coordinatesMixed = (2.1, 3)
// Inferred to be of type (Double, Int)
let x1 = coordinates.0
let y1 = coordinates.1
let coordinatesNamed = (x: 2, y: 3)
// Inferred to be of type (x: Int, y: Int)
let x2 = coordinatesNamed.x
let y2 = coordinatesNamed.y
let coordinates3D = (x: 2, y: 3, z: 1)
let (x3, y3, z3) = coordinates3D
let coordinates3D = (x: 2, y: 3, z: 1)
let x3 = coordinates3D.x
let y3 = coordinates3D.y
let z3 = coordinates3D.z
let (x4, y4, _) = coordinates3D

Mini-exercises

  1. Declare a constant tuple that contains three Int values followed by a Double. Use this to represent a date (month, day, year) followed by an average temperature for that date.
  2. Change the tuple to name the constituent components. Give them names related to the data that they contain: month, day, year and averageTemperature.
  3. In one line, read the day and average temperature values into two constants. You’ll need to employ the underscore to ignore the month and year.
  4. Up until now, you’ve only seen constant tuples. But you can create variable tuples, too. Change the tuple you created in the exercises above to a variable by using var instead of let. Now change the average temperature to a new value.

A whole lot of number types

You’ve been using Int to represent whole numbers. An Int is represented with 64 bits on most modern hardware and with 32 bits on older, or more resource-constrained systems. Swift provides many more number types that use different amounts of storage. For whole numbers, you can use the explicit signed types Int8, Int16, Int32, Int64. These types consume 1, 2, 4, and 8 bytes of storage respectively. Each of these types use 1 bit to represent the sign.

let a: Int16 = 12
let b: UInt8 = 255
let c: Int32 = -100000

let answer = Int(a) + Int(b) + Int(c)  // answer is an Int

Type aliases

A useful feature of Swift is being able to create your own type which is actually an alias of another type. What this means you can do is give a more useful name to your type that describes what it is, but actually underneath it’s just another type. This is known as a type alias.

typealias Animal = String
let myPet: Animal = "Dog"
typealias Coordinates = (Int, Int)
let xy: Coordinates = (2, 4)

A peek behind the curtains: Protocols

Even though there are a dozen different numeric types, they are pretty easy to understand and use, because they all roughly support the same operations. In other words, once you know how to use an Int, using any one of the flavors is straight-forward.

Challenges

Before moving on, here are some challenges to test your knowledge of types and operations. It is best if you try to solve them yourself, but solutions are available if you get stuck. These came with the download or are available at the printed book’s source code link listed in the introduction.

Challenge 1: Coordinates

Create a constant called coordinates and assign a tuple containing two and three to it.

Challenge 2: Named coordinate

Create a constant called namedCoordinate with a row and column component.

Challenge 3: Which are valid?

Which of the following are valid statements?

let character: Character = "Dog"
let character: Character = "🐶"
let string: String = "Dog"
let string: String = "🐶"

Challenge 4. Does it compile?

let tuple = (day: 15, month: 8, year: 2015)
let day = tuple.Day

Challenge 5: Find the error

What is wrong with the following code?

let name = "Matt"
name += " Galloway"

Challenge 6: What is the type of value?

What is the type of the constant named value?

let tuple = (100, 1.5, 10)
let value = tuple.1

Challenge 7: What is the value of month?

What is the value of the constant named month?

let tuple = (day: 15, month: 8, year: 2015)
let month = tuple.month

Challenge 8: What is the value of summary?

What is the value of the constant named summary?

let number = 10
let multiplier = 5
let summary = "\(number) multiplied by \(multiplier) equals \(number * multiplier)"

Challenge 9: Compute the value

What is the sum of a and b, minus c?

let a = 4
let b: Int32 = 100
let c: UInt8 = 12

Challenge 10: Different precision 𝜋s

What is the numeric difference between Double.pi and Float.pi?

Key points

  • Type conversion allows you to convert values of one type into another.
  • Type conversion is required when using an operator, such as the basic arithmetic operators (+, -, *, /), with mixed types.
  • Type inference allows you to omit the type when Swift already knows it.
  • Unicode is the standard for mapping characters to numbers.
  • A single mapping in Unicode is called a code point.
  • The Character data type stores single characters. The String data type stores collections of characters, or strings.
  • You can combine strings by using the addition operator.
  • You can use string interpolation to build a string in-place.
  • You can use tuples to group data into a single data type.
  • Tuples can either be unnamed or named. Their elements are accessed with index numbers for unnamed tuples, or programmer given names for named tuples.
  • There are many kinds of numeric types with different storage and precision capabilities.
  • Type aliases can be used to create a new type that is simply a new name for another type.
  • Protocols are how types are organized in Swift. They describe the common operations that multiple types share.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

© 2022 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.