Chapter 4 Constants, Variables, and Types
In this chapter, you’ll learn how you can store values in the computer’s memory using constants and variables. You’ll also learn how constants and variables have types associated with them, and how these types help you write safer code.
A constant is a name associated with a value in memory. The following example declares a constant named
answer which holds a value of 42:
let answer = 42
This declaration allocates a piece of memory large enough to hold an integer, and assigns it the value 42. The name
answer now refers to this value in memory.
The diagrams in this course represent constants and variables as labeled boxes. The box represents a piece of memory and shows its contents. The label shows the name that refers to this piece of memory:
You can use a constant in an expression by writing its name:
2 * answer + 1
Swift reads the value of the constant from memory and uses that value to evaluate the expression. Remember to use the
print(2 * answer + 1)
So why should you use constants? Wouldn’t it be easier just to use their values instead?
Constants are a great way to represent parameters. Suppose you want to calculate the time it takes for an object dropped from a tall building to hit the ground. The following expression calculates this time for a building with a height of 100 meters:
sqrt(2 * 100.0 / 9.81)
Here, 100.0 is the height of the building, and 9.81 is the Earth’s gravity. By storing these values in constants, the code becomes a lot clearer:
let height = 100.0 let gravity = 9.81 sqrt(2 * height / gravity)
You can improve this even more by also storing the result in a constant:
let height = 100.0 let gravity = 9.81 let time = sqrt(2 * height / gravity) print(time)
When you represent parameters as constants instead of literals, you don’t have to change any calculations when you want to try different parameters. Simply change the values of the parameters and rerun the program:
let height = 120.0 let gravity = 9.81 let time = sqrt(2 * height / gravity) print(time)
Another great use for constants is storing intermediate results. The next example calculates the distance of a throw, given the angle of the throw and the object’s initial velocity:
let angle = 45.0 let velocity = 2.0 let gravity = 9.81 let radians = (angle / 180) * .pi let vx = velocity * cos(radians) let vy = velocity * sin(radians) let time = (2 * vy) / gravity let distance = vx * time print(distance)
This example first declares its parameters as constants. Then, it declares several more constants to store intermediate results. Finally, it uses these constants to calculate the distance of the throw as
vx * time.
Using constants in this way reduces the complexity of your code. For comparison, here’s the calculation of
distance without any intermediate results:
let distance = velocity * cos((angle / 180) * .pi) * (2 * velocity * sin((angle / 180) * .pi)) / gravity
Use constants whenever they make your code easier to understand. Don’t worry about wasting memory; the compiler removes unnecessary constants when it compiles and optimizes your code.
Like a constant, a variable is a name associated with a value in memory. The declaration of a variable uses the keyword
var instead of
var unitsInStock = 12
This code declares a variable named
unitsInStock with an initial value of 12:
Unlike constants, variables are mutable: their value can change as the program runs. To change the value of a variable, you use the assignment operator (
=). The following example reduces the value of
unitsInStock by one:
unitsInStock = unitsInStock - 1
The assignment operator evaluates the expression on its right-hand side and stores the result in the variable on its left-hand side:
Note: You only use the keyword
varto declare a new variable. Don’t repeat it when you assign a value to an existing variable. Doing so is a common beginner’s mistake.
Variables are ideal for storing values that change as your program runs. However, for all other values, you should prefer constants. Here’s why:
- Constants protect against accidental changes. You’ll see an error when you attempt to mutate a constant.
- The compiler produces more performant code when it knows a particular value is constant. It can even remove unnecessary constants entirely.
- By only using variables for values that change, your code becomes easier to understand. Anyone reading the code can tell at a glance which values your program will change and which are constant.
4.2.1 Compound assignment
The previous example used the current value of
unitsInStock to calculate its new value:
unitsInStock = unitsInStock - 1
This is such a common operation that Swift offers a compound assignment operator (
-=) for it:
unitsInStock -= 1
This operator reads the value of
unitsInStock, subtracts one, and stores the result back in
There are plenty more compound assignment operators for you to discover. The next example shows the compound assignment operators for addition (
+=), multiplication (
*=), and division (
/=). Each compound assignment is followed by its equivalent regular assignment:
unitsInStock += 1 unitsInStock = unitsInStock + 1 unitsInStock *= 2 unitsInStock = unitsInStock * 2 unitsInStock /= 2 unitsInStock = unitsInStock / 2
As you can tell, compound assignments are easier to read, which is why you should prefer them over regular assignments.
4.3 Naming rules and guidelines
When picking a name for a constant or variable, these are the rules you must adhere to:
- The name cannot be a reserved keyword, such as
import. These words hold a special meaning in Swift.
- Names may contain digits, but not as the first character. This means
player1is a valid name, but
- Names cannot contain spaces. Most other Unicode characters are allowed.
On top of these rules, the following guidelines are equally important:
- Start the name with a lowercase letter. If the name consists of multiple words, start the extra words with an uppercase letter and don’t separate them. This naming style is known as camel case, of which
unitsInStockis an example.
- Names should be descriptive and informative. Don’t try to make your names as short as possible. Instead, focus on writing code that’s easy to read and understand.
- Use English words so that your code fits in with Swift’s keywords and function names.
In Swift, every constant and variable has a type associated with it. This type determines the values you can assign to that constant or variable.
You decide the type of a constant or variable when you declare it. However, most declarations don’t require an explicit type. Thanks to a feature called type inference, Swift can infer and assign the correct type for you.
Here’s an example from earlier:
var unitsInStock = 12
From this declaration, Swift infers the type of
Int, which is the default type for integers. This means
unitsInStock can only hold integers, not floating-point numbers:
unitsInStock = 11.5 // Invalid!
The size of an
Int depends on your hardware, but it’s usually 64 bits. Swift also has types for fixed-width integers (
Int16, …) and unsigned integers (
UInt8, …), but unless you have a good reason to use them, stick with
Next, consider the following declaration:
let angle = 45.0
Here, Swift infers the type of
Double, which is the default type for floating-point numbers.
As its name implies, values of type
Double are 64-bit double-precision floating-point numbers. Swift also has a 32-bit single-precision type
Float, but unless you have a good reason to use it, use
When you initialize a constant or variable with an expression, the type of the expression determines the type of the constant or variable:
let radians = (angle / 180) * .pi
From this expression, Swift infers the type of
Double. Here’s why:
- The type of
- The type of a literal depends on its context. In this case, Swift knows the division operator requires two operands of the same type, so it infers the type of
Double. The result of the division is a
.piis shorthand for
Double.pi, which is a value of type
Double. Therefore, both operands for the multiplication are of type
Double, and so is the result.
As an exercise, infer the types of all the constants, variables, and expressions in this chapter so far. After you’ve found the correct types, change some of the literals from integer to floating-point — or vice versa — to see how that affects the code.
Most of these changes will result in type errors. Familiarize yourself with these errors as they’re one of the most common kinds of errors you’ll encounter in Swift.
4.4.1 Type annotations
The declaration of a constant or variable can include a type annotation to make the type explicit. Such an annotation is required when Swift is unable to infer a type for you:
var age: Int var height: Double
This code declares variables
height but doesn’t initialize them. This means the contents of
height are unknown. They can be zero or an unknown bit pattern left by a previous application that used this piece of memory.
For safety reasons, Swift doesn’t let you read uninitialized variables:
print(age) // Invalid!
You must assign initial values to
height before you can use them:
age = 36 height = 184.5 print(age) print(height)
Type annotations take precedence over type inference. In the following example, the annotation
: Double overrides the inferred type
var weight: Double = 74
In this particular case, it’s better to use an initial value of 74.0 instead. Rely on type inference where possible and only use type annotations when necessary.
4.4.2 Converting between types
Consider the following expression:
age + height // Invalid!
This expression is invalid because the addition operator requires two operands of the same type, yet
age is an
height is a
Double. To perform this addition, you need to either convert
age to a
Double or convert
height to an
Int. Here’s how you do that:
Double(age) + height age + Int(height)
The result of the first expression is a
Double, whereas the result of the second expression is an
Int. These results are different because the conversion of
Int truncates its value from 184.5 to 184.
Note that these conversions create new values of types
Int. They don’t affect the values stored in
height, nor their types. The type of a constant or variable is fixed during its declaration and cannot be changed later on.
4.4.3 Type safety
Swift requires every constant and variable to have a type, either explicit or inferred. The compiler checks your code to verify that the values you assign are of the correct type. This strict typing adds an additional layer of safety — known as type safety — to your code. In languages that don’t offer type safety, type errors often go undetected during development and show up as bugs when the program is running.
Swift offers even more safety by not performing implicit type conversions. As you’ve seen in the previous example, type conversions can result in a loss of data. A conversion from
Int truncates the fractional part. Even a conversion from
Double can discard information.
Consider the following integer:
This integer has more significant digits than can be represented in a
Double. When you convert this number from
Double, the resulting number is rounded, resulting in a loss of precision:
For these reasons, Swift avoids implicit type conversions. The decision to convert between types and accept the potential data loss is up to you.
Constants and variables can hold all sorts of data, not just numbers. In the next chapter, you’ll learn how you can use text as data.
Before you continue to that chapter, take a small break from reading and apply what you’ve learned so far to solve the upcoming exercises.