Skip to content

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.

Constants

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:

swift
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:

A constant represented as a box

You can use a constant in an expression by writing its name:

swift
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 function if you want to see the value of this expression in your terminal:

swift
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:

swift
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:

swift
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:

swift
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 parameters and rerun the program:

swift
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:

swift
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:

swift
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.

Variables

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 let:

swift
var unitsInStock = 12

This code declares a variable named unitsInStock with an initial value of 12:

A variable represented as a box

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:

swift
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:

unitsInStock has been changed to 11

Note

You only use the keyword var to 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.

Compound assignment

The previous example used the current value of unitsInStock to calculate its new value:

swift
unitsInStock = unitsInStock - 1

This is such a common operation that Swift offers a compound assignment operator (-=) for it:

swift
unitsInStock -= 1

This operator reads the value of unitsInStock, subtracts one, and stores the result back in unitsInStock.

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:

swift
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.

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 let, var, or import. These words hold a special meaning in Swift.
  • Names may contain digits, but not as the first character. This means player1 is a valid name, but 1up is not.
  • 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 unitsInStock is 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.

Types

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:

swift
var unitsInStock = 12

From this declaration, Swift infers the type of unitsInStock as Int, which is the default type for integers. This means unitsInStock can only hold integers, not floating-point numbers:

swift
unitsInStock = 11.5

The size of an Int depends on your hardware, but it’s usually 64 bits. Swift also has types for fixed-width integers (Int8, Int16, ...) and unsigned integers (UInt, UInt8, ...), but unless you have a good reason to use them, stick with Int.

Next, consider the following declaration:

swift
let angle = 45.0

Here, Swift infers the type of angle as 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 Double instead.

When you initialize a constant or variable with an expression, the type of the expression determines the type of the constant or variable:

swift
let radians = (angle / 180) * .pi

From this expression, Swift infers the type of radians as Double. Here’s why:

  1. The type of angle is Double.
  2. 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 180 as Double. The result of the division is a Double as well.
  3. .pi is 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.

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:

swift
var age: Int
var height: Double

This code declares variables age and height but doesn’t initialize them. This means the contents of age and 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:

swift
print(age)  

You must assign initial values to age and height before you can use them:

swift
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 Int:

swift
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.

Converting between types

Consider the following expression:

swift
age + height  

This expression is invalid because the addition operator requires two operands of the same type, yet age is an Int while 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:

swift
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 height from Double to Int truncates its value from 184.5 to 184.

Note that these conversions create new values of types Double and Int. They don’t affect the values stored in age and height, nor their types. The type of a constant or variable is fixed during its declaration and cannot be changed later on.

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 Double to Int truncates the fractional part. Even a conversion from Int to Double can discard information.

Consider the following integer:

swift
1073904854319572423

This integer has more significant digits than can be represented in a Double. When you convert this number from Int to Double, the resulting number is rounded, resulting in a loss of precision:

swift
1.0739048543195725e+18

For these reasons, Swift avoids implicit type conversions. The decision to convert between types and accept the potential data loss is up to you.

Up next

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.