{"id":362,"date":"2024-10-01T10:26:59","date_gmt":"2024-10-01T10:26:59","guid":{"rendered":"https:\/\/permutationcity.co.uk\/bp\/?p=362"},"modified":"2024-10-03T17:36:37","modified_gmt":"2024-10-03T17:36:37","slug":"error-handling","status":"publish","type":"post","link":"https:\/\/permutationcity.co.uk\/bp\/2024\/10\/01\/error-handling\/","title":{"rendered":"Error handling"},"content":{"rendered":"\n<p>I&#8217;ve used a few different error handling techniques since university.\nOver the last few years a couple of other options have appeared.\nLets take a simple problem and see how it works with all of them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"a-simple-problem\">A simple problem<\/h2>\n\n\n\n<p>Let&#8217;s say we want to read a text file containing a list of dates and return them.\nThe file looks something like this:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">Date list\n5\n2001-04-13\n2005-03-23\n2011-11-01\n2022-03-30\n2024-07-15<\/pre><\/div>\n\n\n\n<p>That is: a fixed header, the number of dates to expect, all of the dates line by line.\nThis covers the basics that you might find in any file type:\nfixed items, values that control later parsing, values with detailed formats.\nThis is probably a file produced by a program,\nit outputs the number of items to expect from the list.\nFor a human produced file I would have an arbitrary sized list with a terminator,\nthat&#8217;s easier for someone to write.<\/p>\n\n\n\n<p>In these example programs I&#8217;m going to assume I have access to whatever functions I want.\nI&#8217;ll try to make them obvious and describe their behaviour if necessary.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"no-error-checking\">No error checking<\/h2>\n\n\n\n<p>Ignoring the problem is the easiest way to go about things.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">std::vector&lt;Date&gt; ReadDates(const std::string&amp; filename) {\n    auto* file = FileOpen(filename, &quot;r&quot;);\n    \n    std::ignore = FileGetLine(file);\n    \n    uint32_t count = ParseUint32(FileGetLine(file));\n    \n    std::vector&lt;Date&gt; dates;\n    for (uint32_t i = 0; i &lt; count; i++) {\n        dates.push_back(ParseDate(FileGetLine(file)));\n    }\n    \n    FileClose(file);\n    return dates;\n}<\/pre><\/div>\n\n\n\n<p>This is as simple as we can get.\nEach part of the header is read and assumed to be correct.\nIf there are any problems it&#8217;s unclear what the result would be.\nThe best you could hope for is an empty date vector, at worst a crash.\nYou don&#8217;t really know.<\/p>\n\n\n\n<p>I&#8217;ve deliberately used a old-fashioned approach to <code>FileOpen<\/code>.\nIf you&#8217;re using <code>C++<\/code> then you should use a <code>std::filestream<\/code> which will close automatically in the destructor.\nIt will make this and every other example easier and shorter.\nHowever some languages don&#8217;t have destructors.\nThey might use with-statements or defer keywords instead.\nI went with the <code>FileOpen<\/code> approach just to leave something annoying that had to be cleared up at the end.\nThat&#8217;s often the way with error handling.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"single-return\">Single return<\/h2>\n\n\n\n<p>An easy way of dealing with errors is to have your functions return an error code or\nsimple a success \/ fail boolean.\nOne way to do is to focus on the successes first and leave the failures until the end.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">bool ReadDates(const std::string&amp; filename, std::vector&lt;Date&gt;&amp; dates) {\n    bool success = true;\n    auto* file = FileOpen(filename, &quot;r&quot;);\n    if (file != nullptr) {\n    \n        std::string headerLine;\n        if (FileGetLine(file, headerLine) &amp;&amp; headerLine == &quot;Date list&quot;) {\n        \n            std::string countLine;\n            uint32_t count;\n            if (FileGetLine(file, countLine) &amp;&amp; ParseUint32(countLine, count)) {\n            \n                for (uint32_t i = 0; i &lt; count; i++) {\n                    std::string dateLine;\n                    Date date;\n                    if (FileGetLine(file, dateLine) &amp;&amp; ParseDate(dateLine, date)) {\n                        dates.push_back(date);\n                    }\n                    else {\n                        LogInfo(&quot;Failed to load date line {}&quot;, i);\n                        success = false;\n                    }\n                }\n            }\n            else {\n                LogInfo(&quot;Failed to load header&quot;);\n                success = false;\n            }\n        }\n        else {\n            LogInfo(&quot;Failed to load date count&quot;);\n            success = false;\n        }\n    \n        FileClose(file);\n    }\n    else {\n        LogInfo(&quot;Failed to open file {}&quot;, filename);\n        success = false;\n    }\n    return success;\n}<\/pre><\/div>\n\n\n\n<p>I really don&#8217;t like this.\nThe successful control flow keeps getting indented more and more.\nThis is a really small example and it&#8217;s already further in than I&#8217;d like.\nIt&#8217;s hard to match success \/ fail pairs so you could end up with the wrong message.\nYou have to try and fit the whole thing in your head at once.\nI think it makes the code hard to understand.<\/p>\n\n\n\n<p>Logging error messages is both good and bad.\nIf you expect the function to succeed then in will help with debugging.\nIf you expect the function might fail,\nfor example if you&#8217;re trying to parse random files,\nthen it&#8217;s going to produce a lot of noise.\nI&#8217;m normally going to try and include it because sometimes that&#8217;s what you want.\nThis isn&#8217;t meant to be about exploring the easiest case.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"return-early\">Return early<\/h2>\n\n\n\n<p>We can use the same sort of functions but change the order.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">bool ReadDates(const std::string&amp; filename, std::vector&lt;Date&gt;&amp; dates) {\n    auto* file = FileOpen(filename, &quot;r&quot;);\n    if (file == nullptr) {\n        LogInfo(&quot;Failed to open file {}&quot;, filename);\n        return false;\n    }\n    \n    std::string headerLine;\n    if (!FileGetLine(file, headerLine) || headerLine != &quot;Date list&quot;) {\n        FileClose(file);\n        LogInfo(&quot;Failed to load header&quot;);\n        return false;\n    }\n    \n    std::string countLine;\n    uint32_t count;\n    if (!FileGetLine(file, countLine) || !ParseUint32(countLine, count)) {\n        FileClose(file);\n        LogInfo(&quot;Failed to load date count&quot;);\n        return false;\n    }\n    \n    for (uint32_t i = 0; i &lt; count; i++) {\n        std::string dateLine;\n        Date date;\n        if (!FileGetLine(file, dateLine) || !ParseDate(dateLine, date)) {\n            FileClose(file);\n            LogInfo(&quot;Failed to load date line {}&quot;, i);\n            return false;\n        }\n        dates.push_back(date);\n    }\n\n    FileClose(file);\n    return true;\n}<\/pre><\/div>\n\n\n\n<p>To me this is much easier to read.\nAt the moment this is my standard coding style.\nIt does something and, if it fails, tidies up and returns immediately.\nOnce you&#8217;ve dealt with the error case you can assume it&#8217;s just going to work afterwards.\nThere is less to hold in your head at any one time.\nYou do have to watch out for the <code>return<\/code> keyword.\nHowever, the format normally makes them easy to spot.<\/p>\n\n\n\n<p>Having to repeat <code>FileClose<\/code> in several places is annoying.\nI can easily imagine situations where memory allocations early on would also have to be deleted\nin each failure case.\nAgain, much easier to do with <code>std::stream<\/code> and <code>std::unique_ptr<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"try-catch\">Try-catch<\/h2>\n\n\n\n<p>Exception handling use to be the big new thing.\nI hear less about it nowadays and don&#8217;t use it often.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">std::vector&lt;Date&gt; ReadDates(const std::string&amp; filename) {\n    FILE* file = nullptr;\n\n    try {\n        file = FileOpen(filename, &quot;r&quot;);\n        \n        std::ignore = FileGetLine(file);\n        \n        uint32_t count = ParseUint32(FileGetLine(file));\n        \n        std::vector&lt;Date&gt; dates;\n        for (uint32_t i = 0; i &lt; count; i++) {\n            dates.push_back(ParseDate(FileGetLine(file)));\n        }\n    \n        FileClose(file);\n        return dates;\n    }\n    catch (const std::runtime_error&amp; exception) {\n        if (file != nullptr) {\n            FileClose(file);\n        }\n        throw;\n    }\n}<\/pre><\/div>\n\n\n\n<p>It&#8217;s certainly much clearer than the previous two examples,\nalmost as simple just assuming it&#8217;s going to work.\nIf we assume that the file processing and parsing functions can throw useful <code>std::runtime_error<\/code>\nthen it will also provide debug information.\nHowever, requiring <code>FileClose<\/code> has produced some awkwardness.\nIt would be a bit easier if a <code>finally<\/code> keyword was available.<\/p>\n\n\n\n<p>I think it&#8217;s apparent clearness is one of the reasons we hear less about it now.\nIt&#8217;s easy to program without thinking too much about it.\nAlmost every one of those lines could throw an exception.\nThat&#8217;s a lot of invisible control flow.\nI know that there are edge cases in C++ which it can end up leaking memory if you&#8217;re not careful.\nOther languages might have garbage collection but can have other resource problems.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"short-circuit-logic\">Short-circuit logic<\/h2>\n\n\n\n<p>I have often used a variant with function success \/ fail that relies on the short-circuit behaviour of <code>&amp;&amp;<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">bool ReadDates(const std::string&amp; filename, std::vector&lt;Date&gt;&amp; dates) {\n    bool success = true;\n    \n    auto* file = FileOpen(filename, &quot;r&quot;);\n    success = success &amp;&amp; (file != nullptr);\n    \n    std::string headerLine;\n    success = success &amp;&amp; FileGetLine(file, headerLine);\n    success = success &amp;&amp; headerLine == &quot;Date list&quot;;\n    \n    std::string countLine;\n    success = success &amp;&amp; FileGetLine(file, countLine);\n    uint32_t count;\n    success = success &amp;&amp; ParseUint32(countLine, count);\n    \n    for (uint32_t i = 0; success &amp;&amp; i &lt; count; i++) {\n        std::string dateLine;\n        success = success &amp;&amp; FileGetLine(file, dateLine);\n        Date date;\n        success = success &amp;&amp; ParseDate(dateLine, date);\n        if (success) {\n            dates.push_back(date);\n        }\n    }\n    \n    if (file != nullptr) {\n        FileClose(file);\n    }\n    return success;\n}<\/pre><\/div>\n\n\n\n<p>If <code>success<\/code> remains <code>true<\/code> then the functions will be executed.\nIf it becomes <code>false<\/code> then all remaining functions will be skipped.\nUnfortunately there&#8217;s no allowance to generate error messages here.\nIf you want to know more you&#8217;ll have to add logging or step through it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"optional-values\">Optional values<\/h2>\n\n\n\n<p>Using an <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/optional\"><code>std::optional<\/code><\/a>\nwe can represent a success with it&#8217;s value or a fail together.\nIt provides an <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/optional\/and_then\"><code>and_then<\/code><\/a>\nmethod which calls a given function if it&#8217;s valid or returns another optional value if not.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">std::optional&lt;std::vector&lt;Date&gt;&gt; ReadDates(const std::string&amp; filename) {\n    auto file = FileOpen(filename, &quot;r&quot;);\n    if (!file.has_value()) {\n        LogInfo(&quot;Failed to open file {}&quot;, filename);\n        return nullopt;\n    }\n    \n    const auto headerLine = file.and_then(FileGetLine);\n    if (!headerLine.has_value() || headerLine != &quot;Date list&quot;) {\n        FileClose(file.value());\n        LogInfo(&quot;Failed to load header&quot;);\n        return nullopt;\n    }\n    \n    const auto count = file.and_then(FileGetLine).and_then(ParaseUint32);\n    if (!count.has_value()) {\n        FileClose(file.value());\n        LogInfo(&quot;Failed to load date count&quot;);\n        return nullopt;\n    }\n    \n    std::vector&lt;Date&gt; dates;\n    for (uint32_t i = 0; i &lt; count; i++) {\n        const auto date = file.and_then(FileGetLine).and_then(ParseDate);\n        if (!date.has_value()) {\n            FileClose(file.value());\n            LogInfo(&quot;Failed to load date line {}&quot;, i);\n            return nullopt;\n        }\n        dates.push_back(date);\n    }\n\n    FileClose(file.value());\n    return dates;\n}<\/pre><\/div>\n\n\n\n<p>I&#8217;ve not used <code>and_then<\/code> before. It ends up being very similar to the &#8220;return early&#8221; version before. Rather than a success and values we combine the two. However the if-expression has to be a separate line so we don&#8217;t save any space. I&#8217;m using the <code>has_value()<\/code> and <code>value()<\/code> methods for the optional values. It could be written more compactly using <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/optional\/operator_bool\">automatic convertion<\/a> and <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/optional\/operator*\">dereferencing<\/a>.<\/p>\n\n\n\n<p>Maybe it could be better if we were willing to give up on error messages?<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">Optional&lt;std::vector&lt;Date&gt;&gt; ReadDates(const std::string&amp; filename) {\n    auto file = FileOpen(filename, &quot;r&quot;);\n    \n    const auto header = file.AndThen(FileGetLine).AndThen(ParseString, &quot;Date list&quot;);\n    \n    const auto count = file.And(header).AndThen(FileGetLine).AndThen(ParaseUint32);\n    \n    auto dates = MakeOptional&lt;std::vector&lt;Date&gt;&gt;();\n    for (const uint32_t i : MakeRange(count.or_else(0))) {\n        dates = file.AndThen(FileGetLine).AndThen(ParseDate).AndThen(AppendValue, dates);\n    }\n\n    file.AndThen(FileClose);\n    return dates;\n}<\/pre><\/div>\n\n\n\n<p>I to switch away from <code>std::optional<\/code> to a custom <code>Optional<\/code> class because\nI wanted more from <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/optional\/and_then\"><code>and_then<\/code><\/a>.\nIt just takes a function but I want to give it a function and some additional arguments.\nI also added an <code>And<\/code> method so that <code>count<\/code> can be conditional on both <code>file<\/code> and <code>header<\/code>.<\/p>\n\n\n\n<p>This has the same number of lines as &#8220;no error checking&#8221;.\nI&#8217;m impressed but also unsure about it.\nThis is definitely feels more complicated.\nExecution flows from top to bottom and all the if-statements have been hidden away inside <code>AndThen<\/code>.\nAs each value is <code>Optional<\/code> you are forced to deal with errors,\nyou can&#8217;t just try to pull data from the file if it hasn&#8217;t opened properly.\nI think the biggest potential problem is failing to cascade the success status through properly.\nHere it would have been easy to code it so that a bad header didn&#8217;t matter.\nIt has to be deliberately included using <code>file.And(header)<\/code> and that could be missed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"result-values\">Result values<\/h2>\n\n\n\n<p>Similarly to <code>Optional<\/code> you can create a <code>Result<\/code> type that either has a value or error details.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">Result&lt;std::vector&lt;Date&gt;&gt; ReadDates(const std::string&amp; filename) {\n    auto file = FileOpen(filename, &quot;r&quot;);\n    if (file.IsError()) {\n        return file.AddError(&quot;Failed to open file {}&quot;, filename);\n    }\n    \n    const auto header = file.AndThen(FileGetLine).AndThen(ParseString, &quot;Date list&quot;);\n    if (header.IsError()) {\n        FileClose(file.Value());\n        return header.AddError(&quot;Failed to load header&quot;);\n    }\n    \n    const auto count = file.AndThen(FileGetLine).AndThen(ParaseUint32);\n    if (count.IsError()) {\n        FileClose(file.Value());\n        return count.AddError(&quot;Failed to load date count&quot;);\n    }\n    \n    std::vector&lt;Date&gt; dates;\n    for (uint32_t i = 0; i &lt; count; i++) {\n        const auto date = file.AndThen(FileGetLine).AndThen(ParseDate);\n        if (date.IsError()) {\n            FileClose(file.Value());\n            return date.AddError(&quot;Failed to load date line {}&quot;, i);\n        }\n        dates.push_back(date);\n    }\n\n    FileClose(file.Value());\n    return dates;\n}<\/pre><\/div>\n\n\n\n<p>This manages to have a more compact yet potentially richer set of error messages.\nThe error details generate by, say, <code>ParseUint32<\/code> could be preserved and amended by this functions error message.<\/p>\n\n\n\n<p>Can this be re-written in a similar compact form as <code>Optional<\/code>?<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">Optional&lt;std::vector&lt;Date&gt;&gt; ReadDates(const std::string&amp; filename) {\n    auto file = FileOpen(filename, &quot;r&quot;).\n        IfErrorAdd(&quot;Failed to open file {}&quot;, filename);\n    \n    const auto header = file.AndThen(FileGetLine).AndThen(ParseString, &quot;Date list&quot;).\n        IfErrorAdd(&quot;Failed to load header&quot;);\n    \n    const auto count = file.And(header).AndThen(FileGetLine).AndThen(ParaseUint32).\n        IfErrorAdd(&quot;Failed to load date count&quot;);\n    \n    auto dates = MakeOptional&lt;std::vector&lt;Date&gt;&gt;();\n    for (const uint32_t i : MakeRange(count.or_else(0))) {\n        dates = file.AndThen(FileGetLine).AndThen(ParseDate).AndThen(AppendValue, dates).\n            IfErrorAdd(&quot;Failed to load date line {}&quot;, i);\n    }\n\n    file.AndThen(FileClose);\n    return dates;\n}<\/pre><\/div>\n\n\n\n<p>So yes it can but this might be too far for me.\n<code>IfErrorAdd<\/code> lets non-error values through without change but amends error messages with more information.\nHowever it feels like the error messages are getting in my way of understanding the code.\nFor now I prefer the less compact form.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"on-balance\">On balance<\/h2>\n\n\n\n<p>I think <code>std::optional<\/code>, <code>Optional<\/code> and <code>Result<\/code> all have potential.\nI need a bit more practice with them.\nThe early return technique still has a lot to recommend it, simple to do and understand.<\/p>\n\n\n\n<p>The biggest frustration with all this code was <code>FileClose<\/code>. If you&#8217;re dealing with code that can have a number of error states minimise the amount of extra work required. Have objects that manage their own state or use statements that can tidy up for you.<\/p>\n\n\n\n<p>This can be a particular problem if different libraries want <em>different<\/em> error handling techniques. Some might return raw values, some optional ones, some results and other use exception handling. That would be a mess. If a library doesn&#8217;t provide a compatible system it could be worth wrapping it up. A thin layer around the library to translate into your preferred error handling technique. Here I could have written a templated <a href=\"https:\/\/permutationcity.co.uk\/bp\/2024\/05\/09\/in-what-order\/#defer\"><code>Defer<\/code><\/a> class that can take a lambda and run it when the object was destroyed. That way I could have setup the <code>FileClose<\/code> once and then forgotten about it. Much better.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">P.S.<\/h2>\n\n\n\n<p>Did anyone spot the problem with these examples? I thought of it after the post had been scheduled but before it went live. None of them check that the file is actually finished before closing. According to the format there is a fixed number of dates and <em>that&#8217;s it<\/em>, extra dates are an error. While I could go back and fix it without anyone knowing there&#8217;s also a lesson here. I go on about it enough, <a href=\"https:\/\/permutationcity.co.uk\/bp\/2024\/01\/31\/we-all-make-mistakes\/\">we all make mistakes<\/a>. If these were going in to a code base then they should have had unit tests written and, ideally, a code reviews as well. Here all the examples with error checking are valid but need an extra check which will be, say, 5 lines in the worst case and just 1 in the best case.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve used a few different error handling techniques since university. Over the last few years a couple of other options have appeared. Lets take a simple problem and see how it works with all of them. A simple problem Let&#8217;s say we want to read a text file containing a list of dates and return [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[1],"tags":[26],"class_list":["post-362","post","type-post","status-publish","format-standard","hentry","category-general","tag-languages"],"_links":{"self":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/362","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/comments?post=362"}],"version-history":[{"count":6,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/362\/revisions"}],"predecessor-version":[{"id":379,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/362\/revisions\/379"}],"wp:attachment":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/media?parent=362"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/categories?post=362"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/tags?post=362"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}