{"id":"l-sw-2-4","courseId":"swift-essentials","lang":"en","kind":"lesson","summary":"Describe failures as error enums, throw and propagate them with try, handle them with do-catch, and decide when Swift 6 typed throws are worth it.","html":"<p>What should happen when a user tries to save an expense with no title, a negative amount, or one that blows straight through the month’s food budget? Returning an optional, as you did in the optionals lesson, tells the caller <em>that</em> it failed but not <em>why</em>, and Pocket Budget needs the why to show the right message. Swift’s error handling makes failure part of a function’s signature, with the reasons spelled out as types.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Errors are enums</h2>\n<p>Start by listing the ways recording an expense can fail:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">BudgetError.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\">enum</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> BudgetError</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">Error</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">Equatable </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:#0550AE;--shiki-dark:#79C0FF\"> emptyTitle</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> nonPositiveAmount</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> overLimit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(by: Decimal)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Any type that conforms to <code dir=\"ltr\">Error</code> can be thrown, and an enum with associated values is the natural fit: each case is one failure, and <code dir=\"ltr\">overLimit</code> carries how far over the user would go. <code dir=\"ltr\">Error</code> has no requirements; it marks the type as throwable. <code dir=\"ltr\">Equatable</code> will help with tests in the last lesson.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">throw and try</h2>\n<p>A function that can fail says so with <code dir=\"ltr\">throws</code> and stops with <code dir=\"ltr\">throw</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">CategoryBudget.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\">struct</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> CategoryBudget</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\"> limit: Decimal</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    private</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">set</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent: 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>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    mutating</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> func</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> record</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">throws</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        guard</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> !</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">title.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">trimmingCharacters</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: .whitespaces).</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">isEmpty</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> else</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">            throw</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> BudgetError.emptyTitle</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        }</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        guard</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> amount </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> else</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">            throw</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> BudgetError.nonPositiveAmount</span></span>\n<span class=\"line\"><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\"> newTotal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> spent </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:#CF222E;--shiki-dark:#FF7B72\">        guard</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> newTotal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">&#x3C;=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">else</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">            throw</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> BudgetError.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">overLimit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">by</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: newTotal </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> limit)</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\">        spent </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> newTotal</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<p><code dir=\"ltr\">guard</code> and <code dir=\"ltr\">throw</code> pair perfectly: each guard states a rule, and its <code dir=\"ltr\">else</code> throws the matching error. <code dir=\"ltr\">private(set)</code> lets anyone read <code dir=\"ltr\">spent</code> but only the budget itself change it, so the only way to spend money is through <code dir=\"ltr\">record</code>, which enforces the rules.</p>\n<p>Every call to a throwing function must be marked with <code dir=\"ltr\">try</code>. That keyword is for humans: scan a function for <code dir=\"ltr\">try</code> and you see every line where control might leave early.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">Handling errors with do-catch</h2>\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\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> food </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> CategoryBudget</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">limit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">50</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\">do</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    try</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> food.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">record</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Dinner\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">62</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\">\"Saved\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">} </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">catch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> BudgetError.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">overLimit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> by) {</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\">\"That's </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">by</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> over your food budget\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">} </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">catch</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\">\"Couldn't save: </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">error</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>When <code dir=\"ltr\">record</code> throws, execution jumps straight to the first <code dir=\"ltr\">catch</code> whose pattern matches, skipping <code dir=\"ltr\">print(&quot;Saved&quot;)</code>. Catch clauses use the same pattern matching as <code dir=\"ltr\">switch</code>, so you can bind associated values. The final bare <code dir=\"ltr\">catch</code> handles everything else and gives you the error as a constant named <code dir=\"ltr\">error</code>.</p>\n<p>If a function can’t sensibly handle an error, it doesn’t have to. Mark it <code dir=\"ltr\">throws</code> too, call with <code dir=\"ltr\">try</code> and no <code dir=\"ltr\">do</code>, and the error travels up to its caller.</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>Catch where you can act</span></p>\n<p>Handle an error at the level that can do something useful with it. The budget model can’t show an alert, and a helper that parses CSV can’t decide whether to retry. Usually that means models and helpers throw, and the screen that started the action catches, shows a message and lets the user try again.</p>\n</aside>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 230\" role=\"img\" aria-labelledby=\"l-sw-2-4-t1\"><defs><marker id=\"arrow-l-sw-2-4-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-2-4-t1\">record throws overLimit. saveExpense is marked throws and passes the error up. The Save button handler has a do-catch that catches it and shows a message.</title>\n  <rect class=\"d-box-warn\" x=\"20\" y=\"150\" width=\"190\" height=\"60\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"115\" y=\"177\" text-anchor=\"middle\">record(...)</text>\n  <text class=\"d-label-muted\" x=\"115\" y=\"198\" text-anchor=\"middle\">throw .overLimit</text>\n  <rect class=\"d-box\" x=\"245\" y=\"85\" width=\"190\" height=\"60\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"340\" y=\"112\" text-anchor=\"middle\">saveExpense()</text>\n  <text class=\"d-label-muted\" x=\"340\" y=\"133\" text-anchor=\"middle\">throws: passes it up</text>\n  <rect class=\"d-box-success\" x=\"470\" y=\"20\" width=\"190\" height=\"60\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"565\" y=\"47\" text-anchor=\"middle\">Save button</text>\n  <text class=\"d-label-muted\" x=\"565\" y=\"68\" text-anchor=\"middle\">do-catch: shows alert</text>\n  <path class=\"d-arrow\" d=\"M210 165 L245 135\" marker-end=\"url(#arrow-l-sw-2-4-1)\"/>\n  <path class=\"d-arrow\" d=\"M435 100 L470 70\" marker-end=\"url(#arrow-l-sw-2-4-1)\"/>\n</svg><figcaption>An error travels up until something catches it</figcaption></figure>\n<h2 id=\"sec-4\" tabindex=\"-1\">try? and try!</h2>\n<p>Two shortcuts exist. <code dir=\"ltr\">try?</code> converts the result into an optional: success gives a value, failure gives <code dir=\"ltr\">nil</code>. <code dir=\"ltr\">try!</code> asserts that the call can’t fail and crashes if it does, with the same risk as a force unwrap.</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>Using try? to make the compiler stop complaining</span></p>\n<p><code dir=\"ltr\">try? food.record(title: title, amount: amount)</code> compiles, and the user taps Save and nothing happens: no expense, no message. You threw away the one piece of information the UI needed. Use <code dir=\"ltr\">try?</code> only when you would genuinely ignore the reason, such as deleting a cache file that may not exist.</p>\n</aside>\n<h2 id=\"sec-5\" tabindex=\"-1\">Messages users can read</h2>\n<p><code dir=\"ltr\">print(error)</code> shows <code dir=\"ltr\">overLimit(by: 12)</code>, which is fine for a log and useless in an alert. Conform to <code dir=\"ltr\">LocalizedError</code> to supply human text:</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\">extension</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> BudgetError</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">LocalizedError </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\"> errorDescription: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</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:#0550AE;--shiki-dark:#79C0FF\"> self</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:#1F2328;--shiki-dark:#E6EDF3\"> .emptyTitle</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Give the expense a name.\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .nonPositiveAmount</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Enter an amount greater than zero.\"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">overLimit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> by)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"This puts you </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">by.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">formatted</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">(.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">currency</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">code</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"USD\"</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">))</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</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 style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>Now <code dir=\"ltr\">error.localizedDescription</code> returns that sentence, ready for a SwiftUI alert.</p>\n<h2 id=\"sec-6\" tabindex=\"-1\">Typed throws in Swift 6</h2>\n<p>Plain <code dir=\"ltr\">throws</code> means “can throw any <code dir=\"ltr\">Error</code>”. Swift 6 adds <strong>typed throws</strong>, where the signature names the exact type:</p>\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\">mutating</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> func</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> record</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">String</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: Decimal) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">throws</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(BudgetError) {</span></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">    // same body; inside, `throw .emptyTitle` can drop the type name</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>The payoff is at the call site. When every <code dir=\"ltr\">try</code> in a <code dir=\"ltr\">do</code> block throws <code dir=\"ltr\">BudgetError</code>, the <code dir=\"ltr\">error</code> in <code dir=\"ltr\">catch</code> is a <code dir=\"ltr\">BudgetError</code>, not <code dir=\"ltr\">any Error</code>, so you can switch over it exhaustively with no catch-all. Write <code dir=\"ltr\">do throws(BudgetError)</code> to state that explicitly:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"swift\" data-index=\"5\"><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\">do</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> throws</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(BudgetError) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    try</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> food.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">record</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Snack\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">100</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">} </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">catch</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\"> error {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    case</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> .emptyTitle</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Give it a name\"</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:#1F2328;--shiki-dark:#E6EDF3\"> .nonPositiveAmount</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Amount must be positive\"</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:#1F2328;--shiki-dark:#E6EDF3\"> .</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">overLimit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> by)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"That's </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">by</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">)</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> over budget\"</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<p>The cost is rigidity: once a function promises <code dir=\"ltr\">BudgetError</code>, it can’t start throwing a decoding or network error without changing its signature and every caller. The Swift project’s own guidance is to keep untyped <code dir=\"ltr\">throws</code> as the default and use typed throws inside a module where callers handle every case, as Pocket Budget’s validation does. For networking later in the course you’ll stay with plain <code dir=\"ltr\">throws</code>, because those calls can fail in more ways than you control.</p>\n<p>That completes the modelling section. You can now describe Pocket Budget’s data and its failures precisely. Next, you put that data on screen with SwiftUI.</p>\n","toc":[{"id":"sec-1","text":"Errors are enums","level":2},{"id":"sec-2","text":"throw and try","level":2},{"id":"sec-3","text":"Handling errors with do-catch","level":2},{"id":"sec-4","text":"try? and try!","level":2},{"id":"sec-5","text":"Messages users can read","level":2},{"id":"sec-6","text":"Typed throws in Swift 6","level":2}],"takeaways":["Model the ways an operation can fail as an enum that conforms to <code dir=\"ltr\">Error</code>, with associated values for the details.","Every call to a throwing function is marked with <code dir=\"ltr\">try</code>, so readers can see exactly where control might jump out.","<code dir=\"ltr\">do</code>-<code dir=\"ltr\">catch</code> handles errors; <code dir=\"ltr\">catch</code> clauses can pattern-match specific cases, and a final <code dir=\"ltr\">catch</code> gets the rest as <code dir=\"ltr\">error</code>.","<code dir=\"ltr\">try?</code> turns failure into <code dir=\"ltr\">nil</code> and throws away the reason, so use it only when the reason truly doesn’t matter.","Typed throws (<code dir=\"ltr\">throws(BudgetError)</code>) fit code where callers handle every case; untyped <code dir=\"ltr\">throws</code> stays the better default for public APIs."],"further":[{"title":"Error Handling","url":"https://docs.swift.org/swift-book/documentation/the-swift-programming-language/errorhandling/"},{"title":"LocalizedError","url":"https://developer.apple.com/documentation/foundation/localizederror"}],"quiz":[{"q":"<p><code dir=\"ltr\">func record(...) throws</code>. What does <code dir=\"ltr\">let result = try? budget.record(title: &quot;Tea&quot;, amount: 3)</code> give you when it fails?</p>","options":[{"text":"The error, stored in <code dir=\"ltr\">result</code>.","why":"<code dir=\"ltr\">try?</code> discards the error entirely; you only learn that something failed."},{"text":"<code dir=\"ltr\">nil</code>, and the reason is lost.","why":"Correct. That’s the trade-off with <code dir=\"ltr\">try?</code>, and why it suits only failures you’d ignore anyway."},{"text":"A crash with the error’s description.","why":"That’s <code dir=\"ltr\">try!</code>. <code dir=\"ltr\">try?</code> never crashes."}],"answer":1},{"q":"<p>A function calls <code dir=\"ltr\">try budget.record(...)</code> but has no <code dir=\"ltr\">do</code>-<code dir=\"ltr\">catch</code>. When does that compile?</p>","options":[{"text":"When the function itself is marked <code dir=\"ltr\">throws</code>, so the error propagates to its caller.","why":"Correct. Errors travel up the call chain until something catches them."},{"text":"Never; every <code dir=\"ltr\">try</code> must sit inside a <code dir=\"ltr\">do</code> block.","why":"A throwing function can let errors pass through to its caller without catching them."},{"text":"Always; uncaught errors are logged and ignored.","why":"Swift checks error handling at compile time. An uncaught error from a non-throwing function is a build error."}],"answer":0},{"q":"<p>When is typed throws, such as <code dir=\"ltr\">throws(BudgetError)</code>, the better choice?</p>","options":[{"text":"For every function, because typed errors are always more precise.","why":"Apple’s guidance is the opposite; untyped <code dir=\"ltr\">throws</code> remains the default because it lets an API add new failure types later."},{"text":"For public library APIs that other teams depend on.","why":"That’s where the fixed error type hurts most; adding a failure later becomes a breaking change."},{"text":"For code inside your module where callers handle every case exhaustively.","why":"Correct. That’s where knowing the exact type pays off, with a <code dir=\"ltr\">switch</code> and no catch-all."}],"answer":2}],"exercise":{"kind":"choice","options":["a","b","c","d"],"correct":["d"],"title":"Follow the errors","prompt":"<p>This uses the <code dir=\"ltr\">CategoryBudget</code> and <code dir=\"ltr\">BudgetError</code> from the lesson: <code dir=\"ltr\">record</code> throws <code dir=\"ltr\">.emptyTitle</code> for a blank title, <code dir=\"ltr\">.nonPositiveAmount</code> for an amount of zero or less, and <code dir=\"ltr\">.overLimit(by:)</code> when the new total would pass the limit. Predict everything the loop prints.</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\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> food </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> CategoryBudget</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">limit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">50</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\"> attempts: [(</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\">\"Lunch\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">), (</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">), (</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Dinner\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">45</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\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (title, amount) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> attempts {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    do</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">        try</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> food.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">record</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">title</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: title, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">amount</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: amount)</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\">\"Saved </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">title</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 style=\"color:#CF222E;--shiki-dark:#FF7B72\">catch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> BudgetError.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">overLimit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">let</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> by) {</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\">by</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 style=\"color:#CF222E;--shiki-dark:#FF7B72\">catch</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\">\"Rejected: </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">\\(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">error</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>\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\">(food.spent)</span></span></code></pre></div>\n","hints":["Track <code dir=\"ltr\">spent</code> after each attempt. Does a failed attempt change it?","The second attempt fails before the amount is even checked. Which guard comes first?","For the third attempt, the new total would be 12 + 45. How far is that over 50?"],"explanation":"<p>Lunch passes every guard, so <code dir=\"ltr\">spent</code> becomes 12 and the line prints “Saved Lunch”. The blank title fails the first guard; <code dir=\"ltr\">.emptyTitle</code> doesn’t match the <code dir=\"ltr\">overLimit</code> pattern, so the bare <code dir=\"ltr\">catch</code> prints “Rejected: emptyTitle”. Dinner would bring the total to 57, so <code dir=\"ltr\">record</code> throws <code dir=\"ltr\">.overLimit(by: 7)</code> and the first catch prints “Over by 7”.</p>\n<p>Because <code dir=\"ltr\">record</code> throws before it assigns <code dir=\"ltr\">spent</code>, the failed attempts change nothing, and the final line prints 12. Writing all the checks first and the mutation last is what makes the function safe to call again after a failure.</p>\n","checkLabels":{},"optionText":{"a":{"text":"Saved Lunch / Saved / Saved Dinner / 62","why":"This ignores both guards. A blank title and a total of 57 against a limit of 50 both throw."},"b":{"text":"Saved Lunch / Rejected: emptyTitle / Over by 7 / 57","why":"The over-limit attempt throws before <code dir=\"ltr\">spent = newTotal</code> runs, so the total never reaches 57."},"c":{"text":"Saved Lunch / Over by 7 / 12","why":"The blank title still produces output. It’s caught by the final bare <code dir=\"ltr\">catch</code>, which prints “Rejected: emptyTitle”."},"d":{"text":"Saved Lunch / Rejected: emptyTitle / Over by 7 / 12","why":"Correct. Each failure is caught by the first matching clause, and failed attempts leave <code dir=\"ltr\">spent</code> untouched."}}},"words":697,"readMinutes":3}