{"id":"l-sw-1-3","courseId":"swift-essentials","lang":"en","kind":"lesson","summary":"Store expenses in arrays, dictionaries and sets, loop over them with for-in, and branch with an exhaustive switch that the compiler checks for you.","html":"<p>One expense is a value. A month of expenses is a collection. Pocket Budget needs three shapes of collection: an ordered list of amounts, a lookup from category to monthly limit, and a bag of unique tags. Swift gives you exactly those three, and all of them are typed, so an array of amounts can never accidentally contain a <code dir=\"ltr\">String</code>.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Arrays: ordered, indexed, typed</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> Foundation</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amounts: [Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12.5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4.25</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">60</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">append</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">18</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">count</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)     </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 4</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(amounts[</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])        </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 12.5</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">first</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> as</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> Any</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// Optional(12.5)</span></span></code></pre></div>\n<p><code dir=\"ltr\">[Decimal]</code> reads “array of <code dir=\"ltr\">Decimal</code>”. Indexes start at 0. Notice the difference between <code dir=\"ltr\">amounts[0]</code> and <code dir=\"ltr\">amounts.first</code>: the subscript trusts you and crashes with “Index out of range” on an empty array, while <code dir=\"ltr\">first</code> returns an optional and lets you handle the empty case with the tools from the previous lesson.</p>\n<p>Most of the time you don’t need indexes at all. A <code dir=\"ltr\">for-in</code> loop visits every element:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> total: Decimal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amounts {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    total </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(total)             </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 94.75</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (index, amount) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">enumerated</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">index </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">. </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">amount</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p><code dir=\"ltr\">enumerated()</code> hands you pairs of position and value, which is the safe way to number rows. Ranges work with <code dir=\"ltr\">for-in</code> too, in two flavours:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> day </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">...</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">30</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { }               </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// closed range: 1 through 30</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> i </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">..&#x3C;</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">amounts.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">count</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { }      </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// half-open: stops before count</span></span></code></pre></div>\n<p>The closed range includes its upper bound; the half-open range stops one short, which is exactly what array indexes need.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">Dictionaries: lookups that might miss</h2>\n<p>A dictionary maps keys to values. Pocket Budget keeps a monthly limit per category:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits: [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 300</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Transport\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 120</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent: [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 280</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> foodLimit </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]          </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// Decimal?, Optional(300)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> funLimit </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Fun\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">??</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">       // Decimal, 0</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">spent[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Fun\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">default</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 15</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">          // creates \"Fun\": 15</span></span></code></pre></div>\n<p>Every lookup returns an optional, because the key might not be there. That’s the same safety idea again, now built into a collection. The <code dir=\"ltr\">default:</code> subscript is the idiomatic way to accumulate totals: it reads the existing value or starts from your default, then writes the result back.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Expecting a dictionary to keep its order</span></p>\n<p><code dir=\"ltr\">for (category, limit) in limits</code> visits pairs in an order that can change between runs. If the UI needs a stable order, sort first: <code dir=\"ltr\">for category in limits.keys.sorted()</code>.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">Sets: unique values</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> tags: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">Set</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"work\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"travel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">tags.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">insert</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"work\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)          </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// already there, nothing changes</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(tags.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">count</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)            </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 2</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(tags.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">contains</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"travel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// true</span></span></code></pre></div>\n<p>A set has no order and no duplicates, and <code dir=\"ltr\">contains</code> stays fast no matter how many items it holds. Use it for tags, selected filters and “have I seen this id already?” checks.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">Choosing a collection</h2>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"Scrollable table\" tabindex=\"0\"><table><thead>\n<tr>\n<th>You need</th>\n<th>Use</th>\n<th>Pocket Budget example</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Order, duplicates allowed, access by position</td>\n<td>Array</td>\n<td>This month’s expenses, newest first</td>\n</tr>\n<tr>\n<td>Look up a value by a key</td>\n<td>Dictionary</td>\n<td>Monthly limit for each category</td>\n</tr>\n<tr>\n<td>Membership and uniqueness, order irrelevant</td>\n<td>Set</td>\n<td>Tags on one expense</td>\n</tr>\n</tbody>\n</table></div><p>When in doubt, start with an array. It’s the collection SwiftUI lists display, and it’s the easiest to read in a debugger. Switch to a dictionary when you catch yourself searching an array for “the one with this name”, and to a set when you catch yourself checking for duplicates before every append.</p>\n<p>All three collections are values, not shared objects. <code dir=\"ltr\">var copy = amounts</code> gives you an independent array: appending to <code dir=\"ltr\">copy</code> leaves <code dir=\"ltr\">amounts</code> untouched. That behaviour has a name, value semantics, and it gets its own lesson in the next section because it shapes how you design every model type.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">switch: exhaustive by design</h2>\n<p><code dir=\"ltr\">switch</code> in Swift is much more than a chain of equality checks. It matches ranges, binds values and adds conditions, and the compiler insists that every possible value is handled. Here is how Pocket Budget picks a status message from the percentage of a budget used:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"5\"><div class=\"code-head\"><span class=\"code-title\">BudgetStatus.swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">func</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> status</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">percentUsed</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">Int</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    switch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> percentUsed {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> ..&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Check your numbers\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">..&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">50</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Plenty left\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 50</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">..&#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">90</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"On track\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 90</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">...</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">100</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Nearly at your limit\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    default:</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        return</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Over budget\"</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">status</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">percentUsed</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">95</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// Nearly at your limit</span></span></code></pre></div>\n<p>Two things differ from C-family languages. First, there is no <code dir=\"ltr\">break</code> and no accidental fall-through: once a case matches, the switch is done. Second, remove the <code dir=\"ltr\">default</code> and the build fails with “switch must be exhaustive”, because an <code dir=\"ltr\">Int</code> has values your cases don’t cover. That error looks annoying with integers. With enums, in the next section, it becomes the most useful error in the language: add a new case to your model and the compiler lists every <code dir=\"ltr\">switch</code> you forgot to update.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 150\" role=\"img\" aria-labelledby=\"l-sw-1-3-t1\"><defs><marker id=\"arrow-l-sw-1-3-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-sw-1-3-t1\">A number line split into five cases: below 0, 0 up to 50, 50 up to 90, 90 through 100, and default for everything above 100. Together they cover every integer.</title>\n  <rect class=\"d-box-warn\" x=\"10\" y=\"40\" width=\"110\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"65\" y=\"70\" text-anchor=\"middle\">..&lt;0</text>\n  <rect class=\"d-box-success\" x=\"130\" y=\"40\" width=\"130\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"195\" y=\"70\" text-anchor=\"middle\">0..&lt;50</text>\n  <rect class=\"d-box-accent\" x=\"270\" y=\"40\" width=\"130\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"335\" y=\"70\" text-anchor=\"middle\">50..&lt;90</text>\n  <rect class=\"d-box-primary\" x=\"410\" y=\"40\" width=\"130\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"475\" y=\"70\" text-anchor=\"middle\">90...100</text>\n  <rect class=\"d-box-warn\" x=\"550\" y=\"40\" width=\"120\" height=\"50\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"610\" y=\"70\" text-anchor=\"middle\">default</text>\n  <text class=\"d-label-muted\" x=\"340\" y=\"125\" text-anchor=\"middle\">The ranges never overlap; default catches every other Int</text>\n</svg><figcaption>How Pocket Budget’s status ranges cover every Int</figcaption></figure>\n<p>Cases can also bind the matched value and test it with <code dir=\"ltr\">where</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"6\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> used: Decimal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 15</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit: Decimal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 10</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">switch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> used {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Nothing spent yet\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">case</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">where</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Over by </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> limit</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">default:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Within budget\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Swift 5.9 also made <code dir=\"ltr\">switch</code> and <code dir=\"ltr\">if</code> usable as expressions, so <code dir=\"ltr\">let label = switch percentUsed { … }</code> works when every case produces a single value. Use whichever form reads better; the exhaustiveness rule is the same.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Order your cases from specific to general</span></p>\n<p>Cases are tried top to bottom and the first match wins. Put narrow cases such as <code dir=\"ltr\">case 0:</code> before broad ones such as <code dir=\"ltr\">case let amount where amount &gt; limit:</code>.</p>\n</aside>\n<p>You can now hold a month of data and make decisions about it. The loops in this lesson work, but they’re longhand. Next you’ll package logic into functions and replace most of those loops with closures like <code dir=\"ltr\">filter</code>, <code dir=\"ltr\">map</code> and <code dir=\"ltr\">reduce</code>.</p>\n","toc":[{"id":"sec-1","text":"Arrays: ordered, indexed, typed","level":2},{"id":"sec-2","text":"Dictionaries: lookups that might miss","level":2},{"id":"sec-3","text":"Sets: unique values","level":2},{"id":"sec-4","text":"Choosing a collection","level":2},{"id":"sec-5","text":"switch: exhaustive by design","level":2}],"takeaways":["An array is ordered and indexed from 0; reading past the end crashes, so prefer <code dir=\"ltr\">first</code>, <code dir=\"ltr\">last</code> and <code dir=\"ltr\">for-in</code> over manual indexes.","[object Object]","A set stores unique values with fast <code dir=\"ltr\">contains</code> checks and no order.","A Swift <code dir=\"ltr\">switch</code> must cover every possible value, has no implicit fallthrough, and can match ranges and <code dir=\"ltr\">where</code> conditions."],"further":[{"title":"Collection Types","url":"https://docs.swift.org/swift-book/documentation/the-swift-programming-language/collectiontypes/"},{"title":"Control Flow","url":"https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/"}],"quiz":[{"q":"<p><code dir=\"ltr\">let limits = [&quot;Food&quot;: 300]</code>. What is the type of <code dir=\"ltr\">limits[&quot;Fun&quot;]</code>?</p>","options":[{"text":"<code dir=\"ltr\">Int</code>, with the value 0","why":"Swift doesn’t invent a value for a missing key. You ask for a default explicitly with <code dir=\"ltr\">default:</code>."},{"text":"<code dir=\"ltr\">Int?</code>, with the value <code dir=\"ltr\">nil</code>","why":"Correct. Every dictionary subscript returns an optional, because any key might be missing."},{"text":"It crashes because the key doesn’t exist.","why":"That’s arrays with a bad index. Dictionaries return <code dir=\"ltr\">nil</code> for a missing key."}],"answer":1},{"q":"<p>You <code dir=\"ltr\">switch</code> on a <code dir=\"ltr\">String</code> category and write cases for “Food” and “Transport” only. What does the compiler say?</p>","options":[{"text":"Nothing; unmatched strings fall through silently.","why":"Swift has no silent fall-through for unmatched values. Every value must hit a case."},{"text":"It warns that the switch might be slow.","why":"Performance isn’t the issue. Exhaustiveness is a hard error, not a warning."},{"text":"“Switch must be exhaustive”, so you add a <code dir=\"ltr\">default:</code> case.","why":"Correct. A <code dir=\"ltr\">String</code> has infinitely many values, so only <code dir=\"ltr\">default</code> can cover the rest."}],"answer":2},{"q":"<p>Which collection fits “the tags a user has applied to an expense, with no duplicates”?</p>","options":[{"text":"<code dir=\"ltr\">Set&lt;String&gt;</code>","why":"Correct. A set ignores duplicate inserts and answers <code dir=\"ltr\">contains</code> quickly; tag order doesn’t matter."},{"text":"<code dir=\"ltr\">[String]</code>","why":"An array allows duplicates, so you would have to check before every append."},{"text":"<code dir=\"ltr\">[String: Bool]</code>","why":"It works, but it’s a set in disguise. Use the type that says what you mean."},{"text":"<code dir=\"ltr\">[Int: String]</code>","why":"Integer keys add nothing here; you’d be rebuilding an array with extra steps."}],"answer":0},{"q":"<p><code dir=\"ltr\">let amounts: [Decimal] = []</code>. What does <code dir=\"ltr\">amounts[0]</code> do at runtime?</p>","options":[{"text":"It returns <code dir=\"ltr\">nil</code>.","why":"That’s what <code dir=\"ltr\">amounts.first</code> does. Subscripting an array never returns an optional."},{"text":"It crashes with “Index out of range”.","why":"Correct. Array subscripts trust you; an empty array has no index 0."},{"text":"It returns 0.","why":"Arrays don’t fill gaps with default values."}],"answer":1}],"exercise":{"kind":"choice","options":["a","b","c","d"],"correct":["c"],"title":"Predict the monthly report","prompt":"<p>Read this snippet from Pocket Budget’s monthly report and predict exactly what it prints. Work through each category in order, tracking what the dictionary lookups return.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Swift</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits: [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 300</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Transport\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 120</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent: [</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 280</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">spent[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Fun\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">default</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 15</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> category </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Food\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Transport\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Fun\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> used </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent[category] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">??</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limits[category] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">??</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    switch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> used {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">        print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">category</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">: nothing yet\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">where</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">        print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">category</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">: over by </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> limit</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    default:</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">        print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">category</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">: ok\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","hints":["After line 3, <code dir=\"ltr\">spent</code> has two keys. Which ones, and with what values?","A missing key with <code dir=\"ltr\">?? 0</code> gives 0. That applies to both <code dir=\"ltr\">spent</code> and <code dir=\"ltr\">limits</code>.","“Fun” has no limit at all, so its limit is 0. Is 15 greater than 0?"],"explanation":"<p><code dir=\"ltr\">spent[&quot;Fun&quot;, default: 0] += 15</code> adds a “Fun” entry, so <code dir=\"ltr\">spent</code> is <code dir=\"ltr\">[&quot;Food&quot;: 280, &quot;Fun&quot;: 15]</code>.</p>\n<ul>\n<li><strong>Food</strong>: used 280, limit 300. Not 0, not over the limit, so <code dir=\"ltr\">default</code> prints “Food: ok”.</li>\n<li><strong>Transport</strong>: no entry in <code dir=\"ltr\">spent</code>, so used is 0 and the first case prints “Transport: nothing yet”.</li>\n<li><strong>Fun</strong>: used 15, and there’s no limit, so <code dir=\"ltr\">limits[&quot;Fun&quot;] ?? 0</code> is 0. 15 &gt; 0 prints “Fun: over by 15”.</li>\n</ul>\n<p>The last line is a real product question in disguise: should a category with no limit count as “over”? The code says yes because <code dir=\"ltr\">?? 0</code> chose that default. Defaults are decisions.</p>\n","checkLabels":{},"optionText":{"a":{"text":"Food: ok / Transport: ok / Fun: ok","why":"Transport has nothing spent, so it matches <code dir=\"ltr\">case 0</code> first. And Fun has no limit, which the code treats as 0."},"b":{"text":"Food: ok / Transport: nothing yet / Fun: nothing yet","why":"The <code dir=\"ltr\">default:</code> subscript on line 3 wrote 15 into “Fun”, so it isn’t 0 any more."},"c":{"text":"Food: ok / Transport: nothing yet / Fun: over by 15","why":"Correct. Transport’s missing key becomes 0, and Fun’s missing limit becomes 0, so 15 counts as over."},"d":{"text":"Food: over by 20 / Transport: nothing yet / Fun: over by 15","why":"280 is below Food’s 300 limit, so the <code dir=\"ltr\">where amount &gt; limit</code> case doesn’t match."}}},"words":738,"readMinutes":4}