EduFlow

Section 1 · Swift the Language

Constants, Variables and Types

12 min3 min readChoose wisely

Lesson at a glance

Declare constants and variables, read the types Swift infers for you, and pick the right number type for money in Pocket Budget.

  1. 1let and var
  2. 2Type inference
  3. 3No silent conversions
  4. 4Money is not a Double

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

Every year I review code from new iOS developers, and the most common crash reports trace back to the same few habits: values that change when nobody expected them to, numbers that quietly lose precision, and assumptions the compiler could have caught. Swift is designed to catch exactly those mistakes, but only if you work with the type system instead of around it.

Over this course you build Pocket Budget, a small iPhone app that tracks what you spend. It starts here, with a handful of values in an Xcode playground, and ends as a SwiftUI app on TestFlight. To follow along, open Xcode, choose File › New › Playground, pick the Blank template, and type the examples. A playground runs your code as you type and shows each result in the sidebar.

let and var

Swift has two ways to name a value. let declares a constant, which is assigned once. var declares a variable, which can change.

PocketBudget.playground
let monthlyLimit = 1500
var spentSoFar = 0

spentSoFar = spentSoFar + 42
spentSoFar += 18          // shorthand for the line above
// monthlyLimit = 2000    // error: cannot assign to value: 'monthlyLimit' is a 'let' constant

Use let by default. When a value is a constant, you never have to wonder who changed it. If you later need to change it, the compiler tells you, and Xcode offers a one-click fix to turn let into var. Going the other way, Xcode warns you when a var is never mutated. Treat that warning as a request to tidy up.

Type inference

You didn’t write a single type above, yet every value has one. Swift infers the type from the first value you assign:

Swift
let category = "Coffee"     // String
let cups = 3                // Int
let pricePerCup = 4.5       // Double
let isRecurring = false     // Bool

Option-click any name in Xcode to see its inferred type. You can also write the type yourself with an annotation, which is useful when the literal alone would pick the wrong one:

Swift
let fee: Double = 3         // without the annotation, 3 would be an Int

Once a value has a type, it keeps it. You can’t put a String into cups later. This is what makes Swift code readable months later: a name means one kind of thing, forever.

No silent conversions

Here is the line that surprises people coming from JavaScript or Python:

Swift
let cups = 3
let pricePerCup = 4.5
// let total = cups * pricePerCup   // error: binary operator '*' cannot be applied to operands of type 'Int' and 'Double'
let total = Double(cups) * pricePerCup   // 13.5

Swift never converts an Int to a Double (or back) behind your back. You write the conversion, so the reader can see it. Converting a Double to an Int with Int(13.5) drops the fraction and gives 13, which is exactly the kind of decision you want to be visible in a code review.

Money is not a Double

Double is binary floating point. It’s fast and perfect for distances or animation timing, but it can’t store most decimal fractions exactly. Add ten cents ten times and look at the result:

Swift
import Foundation

var withDouble = 0.0
var withDecimal: Decimal = 0
for _ in 1...10 {
    withDouble += 0.1
    withDecimal += 0.1
}
print(withDouble)    // 0.9999999999999999
print(withDecimal)   // 1

A budget app that says you spent $0.9999999999999999 loses the user’s trust immediately. Decimal, from Foundation, stores base-10 digits, so cents stay exact. Pocket Budget uses Decimal for every amount, and you will see it in almost every lesson from here on.

One catch: a fractional literal such as let tip: Decimal = 0.07 is read as a Double first and then converted, so it can arrive as 0.07000000000000001024. Short example amounts like 4.5 or 12.99 come through clean, but for amounts that matter, build the Decimal from text (Decimal(string: "0.07")) or from whole cents (Decimal(7) / 100).

You now have constants, variables and the types behind them. In the next lesson you meet the type that makes Swift famous for safety: the optional, Swift’s way of saying “there might not be a value here”.

Key takeaways

  • Use let by default and switch to var only when the compiler tells you the value must change.
  • Swift infers a type from the first value you assign, and that type never changes afterwards.
  • Swift never converts between Int and Double silently; you convert explicitly, so mixed-type maths can’t surprise you.
  • Store money as Decimal, not Double, because binary floating point can’t represent most cents exactly.

Further reading

Check your understanding

3 questions

Question 1 of 3

You write let limit = 300 and later limit = 350. What happens?

Question 2 of 3

What type does Swift infer for let coffee = 4.5?

Question 3 of 3

let rent = 1200 and let fee = 2.5 are both declared. Why does rent + fee fail to compile?

Practice

Choose wisely

Which lines compile?

Pocket Budget’s first playground has a few lines that the Swift compiler will reject. Each option below is a complete snippet on its own. Select every snippet that compiles without errors.

Which lines compile?