Posted 6/16/2018.
You can find Part 2 here.
In Part 2 you learned how to declare constants and variables. When we declared let pi = 3.14159
or let email = "test@example.com"
, we didn't seem to care too much that one is a number (pi) and the other is text (an email address). However, you probably noticed that pi was declared without quotes while the email address was declared with quotes. This is because numbers and text are different types of data, and Swift cares very much about this distinction.
We also saw when discussing constants and variables why the self-imposed constraints of constant values are powerful. In this tutorial we'll learn about data types, why Swift is so rigid about the types we use, and why that's another example of how a constraint can make our code safer and easier to understand.
Open your "HelloSwift" Xcode project. You should have the following:
let pi = 3.14159
let email = "test@example.com"
let four = 2 + 2
var printedLines = 0
print(pi)
print(email)
print(four)
printedLines = 3
print(printedLines)
printedLines = 4
Try changing the value of printedLines
to "Hello":
printedLines = "Hello"
Xcode will give you the following error: Cannot assign value of type 'String' to type 'Int'
. What's happening here? Swift recognized that printedLines
is an integer value. We are using it to track how many times we have printed something to the Console. When we try to change the value from the integer 4
to the text "Hello"
, that doesn't make much sense.
To see this even more clearly, imagine that we were able to change the value of printedLines
to "Hello"
. Then we continue on, printing another value to the console and incrementing printedLines
by 1 as follows:
printedLines = printedLines + 1
The above line is a very reasonable thing to do, but what's "Hello" + 1
? This is why the error you got when trying to set printedLines
to "Hello"
is actually powerful, not limiting. This feature of Swift is called Type Safety, and it prevents us from writing code that would lead to undefined behavior like "Hello" + 1
.
Not all programming languages impose this constraint, and some developers argue that languages without type safety offer greater flexibility and control. My view is that type safety is a very good thing that prevents errors and makes code easier to read and understand, both for the original author and the other developers they work with. Swift also has other features, like protocols and generics, which add the flexibility and control type unsafe languages offer while still preventing the programmer from making errors. I'll write more about protocols and generics later!
Now that we've talked about why types are important, let's look at some actual types!
String
In computer science, the term for a piece of text is a "string". We'll use this term from now on to refer to text, whether it's an email address, name, paragraph, or really anything that we would represent with alphanumeric characters and punctuation. Unsurprisingly, the data type for a string in Swift is String
. You've already seen how a String can be declared in Swift:
let email = "test@example.com"
However, this is shorthand (more on that below). We specify the type of a constant or variable in Swift with a colon as follows:
let email: String = "test@example.com"
Notice the colon comes right after the name of the constant, followed by a space, then the type. This is not enforced by the language, but is done by convention.
In Part 1, we printed the String value "Hello, World!" to the Console. Let's declare that as a constant on a new line in our "HelloSwift" project now.
let hello: String = "Hello, World!"
Int & Double
Integer values in Swift are represented with the Int
type, while decimal numbers are usually declared with the Double
type (there are other types that can be used to represent both integers and decimal numbers, but these are by far the most common). We've already declared each of these types:
let pi = 3.14159
var printedLines = 1
To specify the types explicitly, we only need to change the above to the following:
let pi: Double = 3.14159
var printedLines: Int = 1
Since Double
and Int
values are both numbers, you might wonder why we need separate types. After all, 3.14159 + 1
makes a lot more sense than "Hello" + 1
, right? Yes, but in this case we have a variable printedLines
that tracks the number of times we print to the Console, and we can't print to the Console 4.14159 times. Therefore, it's helpful to treat integers and doubles as different data types.
Back in Xcode, try the following:
printedLines = printedLines + pi
Sure enough, you get an error: Binary operator '+' cannot be applied to operands of type 'Int' and 'Double'
. Swift is once again preventing us from making a mistake.
Bool
A Boolean is a special data type that can only have the value true
or false
. It is particularly useful in conditional logic ("if this, then that"). The Swift data type for booleans is called Bool
. We can declare a Bool
as follows:
let isAdult: Bool = false
We've declared a constant that's always false, which is not very helpful. Let's consider a more realistic example. Add the following at the bottom of "main.swift" in Xcode:
let age: Int = 32
let isAdult = age >= 18
print(isAdult)
Here we've declared an integer value to represent a person's age and set isAdult
to be true
if age
is greater than or equal to 18
, otherwise false. The Console should print true
.
As we've seen, we can declare constants and variables without explicitly specifying the data type. When we tried to set printedLines
to "Hello"
and got the error, Cannot assign value of type 'String' to type 'Int'
, we had not yet specified printedLines
as an integer value.
We got the error anyway because Swift tries to infer the type of the value you declare when you don't explicitly specify a type. If you use quotes, it knows you are declaring a String
. If you set declare printedLines
with a value of 0
, it infers that you are declaring an integer. When you declare pi
as 3.14159
, Swift infers the type as Double
. Finally, when you declare a value as true
or false
(or an expression that evaluates to either like age >= 18
), Swift knows the type must be Bool
.
Now that you know about type inference, you do not have to specify the type when declaring a constant or variable. However, you can use your knowledge of type inference to be clear about what you want, or to explicitly specify a type when you need to. For example, if you wanted to treat printedLines
as a Double
, you could do one of the following.
var printedLines = 0.0
Or:
var printedLines: Double = 0
In the first example, we are telling Swift we want a Double
by adding a decimal place. In the second, we are explicitly specifying the type as Double
because we know Swift will otherwise infer the type as Int
.
Type inference allows our code to be more concise. While using type inference may seem to make code more difficult to read at first, as you get more comfortable with types I think you'll find you internalize the inference rules. Code then becomes easier to read, both because it's shorter and because you only see explicitly declared types when they are necessary.
You should now be able to answer these questions:
In this tutorial you learned how to specify types and the benefits of type safety and type inference. You also learned about four of the built-in Swift types, String
, Int
, Double
, and Bool
. There are many more that we'll cover later, and you can also create your own! For example, if you want to represent a book, user, country, network, game, or countless other things and ideas in code, you can declare a custom type. I'll cover that in a future post, but first we'll learn about another basic building block of programming, Functions.