Skip to content

2. Constants, variables & types

What & why

Programs store values. Swift makes you decide up front whether a value can change: let declares a constant, var a variable. This one habit — preferring let — prevents a huge class of bugs.

let and var

let maxPlayers = 4        // constant: can never be reassigned
var score = 0             // variable: can change

score = 10
score += 5                // 15
// maxPlayers = 8         // ERROR: cannot assign to value: 'maxPlayers' is a 'let' constant

Rule of thumb: write let everywhere. Change it to var only when the compiler tells you that you reassign it.

A constant can be declared first and assigned once later:

let greeting: String
if score > 10 {
    greeting = "High score!"
} else {
    greeting = "Keep going"
}
print(greeting)

Types and type inference

Swift is statically typed: every value has a type known at compile time. You rarely have to write it, because the compiler infers it:

let age = 30              // Int
let pi = 3.14159          // Double
let name = "Ada"          // String
let isReady = true        // Bool
let initial: Character = "A"   // must annotate: a plain "A" would infer String

Add a type annotation with : Type when inference can't pick what you want, or to be explicit:

let ratio: Double = 3         // 3.0 — the literal adapts to the annotation
let small: UInt8 = 200
var total: Int                // declared, assigned later

Check a type with type(of:):

print(type(of: pi))           // Double

The core types

Type Holds Example
Int whole numbers (64-bit on modern platforms) 42, -7, 1_000_000
Double 64-bit floating point 3.14, 2.5e3
Float 32-bit floating point (rarely needed) 1.5
Bool true / false true
String text "hello"
Character a single user-perceived character "a", "🙂"

There are also sized integers — Int8, Int16, Int32, Int64, UInt8, … UInt64 — for binary formats and APIs that need exact sizes. Use plain Int for everyday counting and indexing, even for values that can't be negative.

Underscores make big literals readable:

let million = 1_000_000
let mask = 0b1010_1010       // binary
let hex = 0xFF               // hexadecimal

No implicit conversions

Swift never silently converts between numeric types:

let items = 3
let price = 4.5
// let total = items * price      // ERROR: binary operator '*' cannot be applied to 'Int' and 'Double'
let total = Double(items) * price // 13.5 — convert explicitly

Converting down truncates:

let whole = Int(9.99)          // 9, not 10 — the fractional part is dropped

Converting from text can fail, so it returns an optional (see Optionals):

let n = Int("42")              // Optional(42)
let bad = Int("forty")         // nil

Tuples

A tuple groups a few values of possibly different types:

let point = (x: 3, y: 4)
print(point.x, point.y)        // 3 4

let (w, h) = (1920, 1080)      // decompose into two constants
let (status, _) = (404, "Not Found")   // _ ignores a value

Tuples are great for quick, lightweight groupings (especially function results). For anything longer-lived, use a struct (Intermediate, lesson 1).

Naming

  • lowerCamelCase for variables, constants, functions: userCount, fetchData()
  • UpperCamelCase for types: String, TaskItem
  • Names can contain almost any Unicode character, but be kind to your teammates.
  • Reserved words (like class, func, in) need backticks to be used as names — just pick another name.

typealias

Give an existing type a clearer name:

typealias Meters = Double
let height: Meters = 1.82

Common mistakes

  • Using var for everything. The compiler even warns: "variable was never mutated; consider changing to 'let'". Listen to it.
  • Mixing Int and Double in arithmetic without converting.
  • Assuming Int("12.5") works. It returns nil — Int only parses whole numbers. Use Double("12.5").
  • Using the wrong default for Character. let c = "a" is a String. Annotate : Character if you need one.
  • Using UInt "because it can't be negative". Subtractions that go below zero crash at runtime. Prefer Int.

Exercises

  1. Declare a constant for your birth year and a variable for the current year. Print your age.
  2. Declare let a = 7 and let b = 2.0. Print a / b. (You'll need a conversion.)
  3. Print type(of:) for 42, 42.0, "42", true, (1, "a"), and [1, 2].
  4. Convert "123", "12.3", and "abc" to Int and print each result. What do you see, and why?
  5. Create a tuple person = (name: "Grace", age: 85), then decompose it into two separate constants.
  6. Try to reassign a let. Read the error, then fix it two ways (change to var, or remove the reassignment).

Recap

  • let for values that never change (default), var for ones that do.
  • Types are inferred; annotate with : Type when needed.
  • Int, Double, Bool, String, Character cover most everyday needs.
  • No implicit numeric conversion — use Double(x), Int(x).
  • Tuples bundle a few values together.

Next: Numbers & math →