27.5 · Values, optionals, patterns, order and isolation: ten more checked puzzles
Ten more programs whose output was run, each built around a rule people guess wrong.
Mental model. Name the rule first (shared reference, snapshot, grapheme, nested optional, first match, observer rules, autoclosure, requirement vs extension, synthesised init, isolation), then predict.
Values and strings
Shared references, snapshots and text.
- What does copying a struct that holds a class reference, or building an array with Array(repeating:), actually share?
Assigning a struct copies its stored properties one by one. An Array property is copied lazily (copy-on-write), so appending to h2.tags leaves h1.tags alone. A… - How do dictionary default subscripts and nil assignment behave when you group and count, and why is removing inside a for-in over the same array safe?
for x in a iterates over a copy of the array taken when the loop starts. Appending to a inside the loop triggers copy-on-write, so the loop still visits only… - Why do count, unicodeScalars, utf16 and utf8 give different numbers for the same string?
String.count counts extended grapheme clusters, what a reader sees as one character. unicodeScalars counts code points, utf16 counts UTF-16 units (what…
Optionals and patterns
Nested optionals and switch order.
- What do nested optionals and nil assignments do: Int??, dictionaries of optionals, optional chaining and Int(String)?
Int?? is an optional wrapping an optional. .some(nil) is not nil (a == nil is false), while a plain nil is. In a [String: Int?] the subscript returns Int??… - In what order does switch try its cases, and what do where, fallthrough, for-case and ~= do?
A switch takes the first case that matches, top to bottom, so order matters: (4, 4) is "diagonal" because that case comes before (1...3, _), (9, 9) is diagonal…
Observers, order and dispatch
Order of evaluation and which method runs.
- In what order do willSet and didSet run across a subclass, an initialiser, a didSet that assigns, and an inout argument?
Observers do not run for assignments in the owning class's own initialiser: v = 1 in Base.init prints nothing, even though Sub overrides the observers. After… - In what order are operands, default arguments, autoclosures and assert conditions evaluated?
Operands evaluate left to right, but &&, || and ?? take their right side as an @autoclosure, so it runs only when needed: a c e f g shows b and d never ran… - Which method runs through a protocol extension: when is a call dispatched dynamically and when statically?
A method that is a protocol requirement is dispatched through the witness table, so the conforming type's version wins even through the protocol type…
Codable and isolation
Synthesised decoding and where async code runs.
- How does synthesised Decodable treat missing keys, nulls, default values and number types?
The synthesised init(from:) ignores property defaults: var tags: [String] = [] is still required, so a payload without tags throws keyNotFound (and one without… - Where do a nonisolated async function, @concurrent, @MainActor and Task run when called from the main actor?
From a @MainActor function: a @MainActor function stays on main; Task { } inherits the main actor; Task.detached does not. An ordinary nonisolated async…