Step 1 of 5 · Reading · ~4 min
Learn
Strings and Optionals
Optionals
Every language has to answer one question: what does a variable hold when there is nothing to hold? Most answer "null", and then let you call methods on it anyway. Swift answers with a type.
Stringalways contains a string. There is no state in which it is empty of value.String?— read "optional String" — contains either a string ornil.
They are different types, and the compiler will not let you confuse them.
var name: String = "Alice"
var maybeName: String? = nil
print(name.count)
// print(maybeName.count)
// error: value of optional type 'String?' must be unwrapped
// to a value of type 'String'
//> 5
That error is the entire feature. The null-pointer crash that other languages discover in production, Swift discovers while you are typing.
Where optionals come from
You do not usually declare them; you receive them. Anything that can legitimately fail to produce a value hands you an optional:
| Expression | Type | Why it can be nil |
|---|---|---|
readLine() | String? | stdin might be at end of input |
Int("42") | Int? | the text might not be a number |
[3, 8, 2].max() | Int? | the array might be empty |
dict["missing"] | Value? | the key might not be there |
"".first | Character? | the string might be empty |
print(String(describing: Int("42")))
print(String(describing: Int("cat")))
print(String(describing: [Int]().max()))
//> Optional(42)
//> nil
//> nil
Notice the first line: an unwrapped optional prints as Optional(42), not 42. If a test ever
expects 42 and you get Optional(42), you forgot to unwrap.
Four ways to get the value out
1. if let — do something only when there is a value.
let raw = "42"
if let n = Int(raw) {
print("parsed \(n)")
} else {
print("not a number")
}
//> parsed 42
Inside the braces, n is a plain Int. The optional is gone.
2. guard let — bail out early, then carry on unwrapped.
func describe(_ raw: String) -> String {
guard let n = Int(raw) else {
return "not a number"
}
return "twice \(raw) is \(n * 2)"
}
print(describe("21"))
print(describe("cat"))
//> twice 21 is 42
//> not a number
The difference from if let matters: n stays in scope for the rest of the function, so the
happy path is never indented. A guard's else block must leave the scope — return, throw,
break or continue.
3. ?? — supply a fallback value.
let missing: String? = nil
print(missing ?? "anonymous")
print(missing?.count ?? 0)
//> anonymous
//> 0
missing?.count is optional chaining: if missing is nil the whole expression is nil and
.count is never called, so ?? 0 catches it.
4. ! — force unwrap, and crash if you were wrong.
let n = Int("42")!
This says "I guarantee this is not nil." When the guarantee is false the process dies on the spot — the same class of failure as a null-pointer exception, just made explicit.
Why do the starters keep using !?
You have already seen Int(readLine()!)! several times. Two force-unwraps: one because
readLine() returns String?, one because Int(_:) returns Int?. It is there so the earliest
exercises could read input before you knew what an optional was — it is scaffolding, not style.
Now that you do know, here is the same plumbing written the way real code is written:
✗ Crashes on unexpected input
let n = Int(readLine()!)!
✓ Handles it
guard let line = readLine(), let n = Int(line) else {
print("bad input")
exit(1)
}
One guard can unwrap several optionals in a row, separated by commas — and each binding can be
used by the ones after it. If any of them is nil, the whole else runs.
Your exercise
Read one line and print its length, printing 0 when the line is empty.
The mistake the grader catches is printing an optional. readLine() hands you a String?;
the starter already applies ?? "" to turn it into a String, so line.count is a plain Int.
If you remove that ?? and print readLine()?.count instead, the output becomes Optional(5)
where the test wants 5, and nil where it wants 0. Also note the empty-line test: an empty
string's .count is already 0, so no if is needed — the second visible test passes for free
once the optional is handled.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…