{"id":31951,"date":"2023-04-18T18:53:41","date_gmt":"2023-04-18T18:53:41","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=31951"},"modified":"2023-04-18T18:53:41","modified_gmt":"2023-04-18T18:53:41","slug":"cpp23s-optional-and-expected","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/cpp23s-optional-and-expected\/","title":{"rendered":"Functional exception-less error handling with C++23&#8217;s optional and expected"},"content":{"rendered":"<p><em>This post is an updated version of <a href=\"https:\/\/blog.tartanllama.xyz\/optional-expected\/\">one I made over five years ago<\/a>, now that everything I talked about is in the standard and implemented in Visual Studio.<\/em><\/p>\n<p>In software things can go wrong. Sometimes we might expect them to go wrong. Sometimes it&#8217;s a surprise. In most cases we want to build in some way of handling these misfortunes. Let&#8217;s call them <a href=\"https:\/\/wg21.link\/p0157\">disappointments<\/a>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/stdoptional-how-when-and-why\/\"><code>std::optional<\/code> was added in C++17<\/a> to provide a new standard way of expressing disappointments and more, and it has been extended in C++23 with <a href=\"https:\/\/wg21.link\/p0798\">a new interface inspired by functional programming<\/a>.<\/p>\n<p><code>std::optional&lt;T&gt;<\/code> expresses &#8220;either a <code>T<\/code> or nothing&#8221;. C++23 comes with a new type, <a href=\"https:\/\/wg21.link\/P0323\"><code>std::expected&lt;T,E&gt;<\/code><\/a> which expresses &#8220;either the expected <code>T<\/code>, or some <code>E<\/code> telling you what went wrong&#8221;. This type also comes with that <a href=\"https:\/\/wg21.link\/p2505\">special new functional interface<\/a>. As of <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">Visual Studio 2022 version 17.6 Preview 3<\/a>, all of these features are available in our standard library. Armed with an STL implementation you can try yourself, I&#8217;m going to exhibit how to use <code>std::optional<\/code>&#8216;s new interface, and the new <code>std::expected<\/code> to handle disappointments.<\/p>\n<p>One way to express and handle disappointments is exceptions:<\/p>\n<pre><code class=\"language-cpp\">void pet_cat() {\r\n    try {\r\n        auto cat = find_cat();\r\n        scratch_behind_ears(cat);\r\n    }\r\n    catch (const no_cat_found&amp; err) {\r\n        \/\/oh no\r\n        be_sad();\r\n    }\r\n}<\/code><\/pre>\n<p>There are a myriad of discussions, resources, rants, tirades, and debates about the value of exceptions<sup><a href=\"https:\/\/www.youtube.com\/watch?v=XVofgKH-uu4\">1<\/a><a href=\"https:\/\/stackoverflow.com\/questions\/1736146\/why-is-exception-handling-bad\">2<\/a><a href=\"https:\/\/stackoverflow.com\/questions\/13835817\/are-exceptions-in-c-really-slow\">3<\/a><a href=\"https:\/\/www.shanekirk.com\/2015\/06\/c-exceptions-the-good-the-bad-and-the-ugly\/\">4<\/a><a href=\"https:\/\/www.acodersjourney.com\/2016\/08\/top-15-c-exception-handling-mistakes-avoid\/\">5<\/a><a href=\"https:\/\/mortoray.com\/2012\/04\/02\/everything-wrong-with-exceptions\/\">6<\/a><\/sup>, and I will not repeat them here. Suffice to say that there are cases in which exceptions are not the best tool for the job. For the sake of being uncontroversial, I&#8217;ll take the example of disappointments which are expected within reasonable use of an API.<\/p>\n<p>The Internet loves cats. Suppose that you and I are involved in the business of producing the cutest images of cats the world has ever seen. We have produced a high-quality C++ library geared towards this sole aim, and we want it to be at the bleeding edge of modern C++.<\/p>\n<p>A common operation in feline cutification programs is to locate cats in a given image. How should we express this in our API? One option is exceptions:<\/p>\n<pre><code class=\"language-cpp\">\/\/ Throws no_cat_found if a cat is not found.\r\nimage_view find_cat (image_view img);<\/code><\/pre>\n<p>This function takes a view of an image and returns a smaller view which contains the first cat it finds. If it does not find a cat, then it throws an exception. If we&#8217;re going to be giving this function a million images, half of which do not contain cats, then that&#8217;s a <em>lot<\/em> of exceptions being thrown. In fact, we&#8217;re pretty much using exceptions for control flow at that point, which is <a href=\"https:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#e3-use-exceptions-for-error-handling-only\">A Bad Thing<\/a>\u2122.<\/p>\n<p>What we really want to express is a function which either returns a cat if it finds one, or it returns nothing. Enter <code>std::optional<\/code>.<\/p>\n<pre><code class=\"language-cpp\">std::optional&lt;image_view&gt; find_cat (image_view img);<\/code><\/pre>\n<p><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/optional\"><code>std::optional<\/code><\/a> was introduced in C++17 for representing a value which may or may not be present. It is intended to be a vocabulary type &#8212; i.e. the canonical choice for expressing some concept in your code. The difference between this signature and the previous one is powerful; we&#8217;ve moved the description of what happens on an error from the documentation into the type system. Now it&#8217;s impossible for the user to forget to read the docs, because the compiler is reading them for us, and you can be sure that it&#8217;ll shout at you if you use the type incorrectly.<\/p>\n<p>Now we&#8217;re ready to use our <code>find_cat<\/code> function along with some other friends from our library to make embarrassingly adorable pictures of cats:<\/p>\n<pre><code class=\"language-cpp\">std::optional&lt;image_view&gt; get_cute_cat (image_view img) {\r\n    auto cropped = find_cat(img);\r\n    if (!cropped) {\r\n      return std::nullopt;\r\n    }\r\n\r\n    auto with_tie = add_bow_tie(*cropped);\r\n    if (!with_tie) {\r\n      return std::nullopt;\r\n    }\r\n\r\n    auto with_sparkles = make_eyes_sparkle(*with_tie);\r\n    if (!with_sparkles) {\r\n      return std::nullopt;\r\n    }\r\n\r\n    return add_rainbow(make_smaller(*with_sparkles));\r\n}<\/code><\/pre>\n<p>Well this is&#8230; okay. The user is made to explicitly handle what happens in case of an error, so they can&#8217;t forget about it, which is good. But there are two issues with this:<\/p>\n<ol>\n<li>There&#8217;s no information about <em>why<\/em> the operations failed.<\/li>\n<li>There&#8217;s too much noise; error handling dominates the logic of the code.<\/li>\n<\/ol>\n<p>I&#8217;ll address these two points in turn.<\/p>\n<h3>Why did something fail?<\/h3>\n<p><code>std::optional<\/code> is great for expressing that some operation produced no value, but it gives us no information to help us understand why this occurred; we&#8217;re left to use whatever context we have available, or (please, no) output parameters. What we want is a type which either contains a value, or contains some information about why the value isn&#8217;t there. This is called <code>std::expected<\/code>.<\/p>\n<p>With <code>std::expected<\/code> our code might look like this:<\/p>\n<pre><code class=\"language-cpp\">std::expected&lt;image_view, error_code&gt; get_cute_cat (image_view img) {\r\n    auto cropped = find_cat(img);\r\n    if (!cropped) {\r\n      return no_cat_found;\r\n    }\r\n\r\n    auto with_tie = add_bow_tie(*cropped);\r\n    if (!with_tie) {\r\n      return cannot_see_neck;\r\n    }\r\n\r\n    auto with_sparkles = make_eyes_sparkle(*with_tie);\r\n    if (!with_sparkles) {\r\n      return cat_has_eyes_shut;\r\n    }\r\n\r\n    return add_rainbow(make_smaller(*with_sparkles));\r\n}<\/code><\/pre>\n<p>Now when we call <code>get_cute_cat<\/code> and don&#8217;t get a lovely image back, we have some useful information to report to the user as to why we got into this situation.<\/p>\n<h3>Noisy error handling<\/h3>\n<p>Unfortunately, with both the <code>std::optional<\/code> and <code>std::expected<\/code> versions, there&#8217;s still a lot of noise. This is a disappointing solution to handling disappointments.<\/p>\n<p>What we really want is a way to express the operations we want to carry out while pushing the disappointment handling off to the side. As is becoming increasingly trendy in the world of C++, we&#8217;ll look to the world of functional programming for help. In this case, the help comes in the form of <code>transform<\/code> and <code>and_then<\/code>.<\/p>\n<p>If we have some <code>std::optional<\/code> and we want to carry out some operation on it if and only if there&#8217;s a value stored, then we can use <code>transform<\/code>:<\/p>\n<pre><code class=\"language-cpp\">cat make_cuter(cat);\r\n\r\nstd::optional&lt;cat&gt; result = maybe_get_cat().transform(make_cuter);\r\n\/\/use result<\/code><\/pre>\n<p>This code is roughly equivalent to:<\/p>\n<pre><code class=\"language-cpp\">cat make_cuter(cat);\r\n\r\nauto opt_cat = maybe_get_cat();\r\nif (opt_cat) {\r\n   cat result = make_cuter(*opt_cat);\r\n   \/\/use result\r\n}<\/code><\/pre>\n<p>If we want to carry out some operation <em>which could itself fail<\/em> then we can use <code>and_then<\/code>:<\/p>\n<pre><code class=\"language-cpp\">std::optional&lt;cat&gt; maybe_make_cuter (cat);\r\n\r\nstd::optional&lt;cat&gt; result = maybe_get_cat().and_then(maybe_make_cuter);\r\n\/\/use result<\/code><\/pre>\n<p>This code is roughly equivalent to:<\/p>\n<pre><code class=\"language-cpp\">std::optional&lt;cat&gt; maybe_make_cuter (const cat&amp;);\r\n\r\nauto opt_cat = maybe_get_cat();\r\nif (opt_cat) {\r\n   std::optional&lt;cat&gt; result = maybe_make_cuter(*opt_cat);\r\n   \/\/use result\r\n}<\/code><\/pre>\n<p><code>and_then<\/code> and <code>transform<\/code> for <code>expected<\/code> act in much the same way as for <code>optional<\/code>: if there is an expected value then the given function will be called with that value, otherwise the stored unexpected value will be returned. Additionally, there is a <code>transform_error<\/code> function which allows mapping functions over unexpected values.<\/p>\n<p>The real power of these functions comes when we begin to chain operations together. Let&#8217;s look at that original <code>get_cute_cat<\/code> implementation again:<\/p>\n<pre><code class=\"language-cpp\">std::optional&lt;image_view&gt; get_cute_cat (image_view img) {\r\n    auto cropped = find_cat(img);\r\n    if (!cropped) {\r\n      return std::nullopt;\r\n    }\r\n\r\n    auto with_tie = add_bow_tie(*cropped);\r\n    if (!with_tie) {\r\n      return std::nullopt;\r\n    }\r\n\r\n    auto with_sparkles = make_eyes_sparkle(*with_tie);\r\n    if (!with_sparkles) {\r\n      return std::nullopt;\r\n    }\r\n\r\n    return add_rainbow(make_smaller(*with_sparkles));\r\n}<\/code><\/pre>\n<p>With <code>transform<\/code> and <code>and_then<\/code>, our code transforms into this:<\/p>\n<pre><code class=\"language-cpp\">std::optional&lt;image_view&gt; get_cute_cat (image_view img) {\r\n    return find_cat(img)\r\n           .and_then(add_bow_tie)\r\n           .and_then(make_eyes_sparkle)\r\n           .transform(make_smaller)\r\n           .transform(add_rainbow);\r\n}<\/code><\/pre>\n<p>With these two functions we&#8217;ve successfully pushed the error handling off to the side, allowing us to express a series of operations which may fail without interrupting the flow of logic to test an <code>optional<\/code>. For more discussion about this code and the equivalent exception-based code, I&#8217;d recommend reading <a href=\"https:\/\/twitter.com\/supahvee1234\">Vittorio Romeo<\/a>&#8216;s <a href=\"https:\/\/vittorioromeo.info\/index\/blog\/adts_over_exceptions.html\">Why choose sum types over exceptions?<\/a> article.<\/p>\n<h3>A theoretical aside<\/h3>\n<p>I didn&#8217;t make up <code>transform<\/code> and <code>and_then<\/code> off the top of my head; other languages have had equivalent features for a long time, and the theoretical concepts are common subjects in <a href=\"https:\/\/bartoszmilewski.com\/2014\/10\/28\/category-theory-for-programmers-the-preface\/\">Category Theory<\/a>.<\/p>\n<p>I won&#8217;t attempt to explain all the relevant concepts in this post, as others have done it far better than I could. The basic idea is that <code>transform<\/code> comes from the concept of a <em>functor<\/em>, and <code>and_then<\/code> comes from <em>monads<\/em>. These two functions are called <code>fmap<\/code> and <code>&gt;&gt;=<\/code> (bind) in Haskell. The best description of these concepts which I have read is <a href=\"https:\/\/adit.io\/posts\/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html\">Functors, Applicatives, And Monads In Pictures<\/a> by Aditya Bhargava. Give it a read if you&#8217;d like to learn more about these ideas.<\/p>\n<h3>A note on overload sets<\/h3>\n<p>One use-case which is annoyingly verbose is passing overloaded functions to <code>transform<\/code> or <code>and_then<\/code>. For example:<\/p>\n<pre><code class=\"language-cpp\">cat make_cuter(cat);\r\n\r\nstd::optional&lt;cat&gt; c;\r\nauto cute_cat = c.transform(make_cuter);<\/code><\/pre>\n<p>The above code works fine. But as soon as we add another overload to <code>make_cuter<\/code>:<\/p>\n<pre><code class=\"language-cpp\">cat make_cuter(cat);\r\ndog make_cuter(dog);\r\n\r\nstd::optional&lt;cat&gt; c;\r\nauto cute_cat = c.transform(make_cuter);<\/code><\/pre>\n<p>then it fails to compile, because it&#8217;s not clear which overload we want to pass to transform.<\/p>\n<p>One solution for this is to use a generic lambda:<\/p>\n<pre><code class=\"language-cpp\">std::optional&lt;cat&gt; c;\r\nauto cute_cat = c.transform([](auto x) { return make_cuter(x); });<\/code><\/pre>\n<p>Another is a <code>LIFT<\/code> macro:<\/p>\n<pre><code class=\"language-cpp\">#define FWD(...) std::forward&lt;decltype(__VA_ARGS__)&gt;(__VA_ARGS__)\r\n#define LIFT(f) \\\r\n    [](auto&amp;&amp;... xs) noexcept(noexcept(f(FWD(xs)...))) -&gt; decltype(f(FWD(xs)...)) \\\r\n    { return f(FWD(xs)...); }\r\n\r\nstd::optional&lt;cat&gt; c;\r\nauto cute_cat = c.transform(LIFT(make_cuter));<\/code><\/pre>\n<p>Personally I hope to see <a href=\"https:\/\/wg21.link\/p0834\">overload set lifting<\/a> in some form get into the standard so that we don&#8217;t need to bother with the above solutions.<\/p>\n<p>If you want to read more about specifically this problem, I have a <a href=\"https:\/\/blog.tartanllama.xyz\/passing-overload-sets\/\">whole blog post<\/a> on it.<\/p>\n<h3>Try them out<\/h3>\n<p>The functional extensions to <code>std::expected<\/code> and <code>std::optional<\/code> are available in <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">Visual Studio 2022 version 17.6 Preview 3<\/a>. Please try them out and let us know what you think! If you have any questions, comments, or issues with the features, you can comment below, or reach us via email at <a href=\"mailto:visualcpp@microsoft.com\">visualcpp@microsoft.com<\/a> or via Twitter at <a href=\"https:\/\/twitter.com\/visualc\">@VisualC<\/a>.<\/p>\n<p>If you&#8217;re stuck on old versions of C++, I have written implementations of <code>optional<\/code> and <code>expected<\/code> with the functional interfaces as single-header libraries, released under the <a href=\"https:\/\/creativecommons.org\/share-your-work\/public-domain\/cc0\/\">CC0<\/a> license. You can find them at <a href=\"https:\/\/github.com\/TartanLlama\/optional\"><code>tl::optional<\/code><\/a> and <a href=\"https:\/\/github.com\/TartanLlama\/expected\"><code>tl::expected<\/code><\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>C++23&#8217;s new facilities for handling disappointments without exceptions.<\/p>\n","protected":false},"author":706,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-31951","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus"],"acf":[],"blog_post_summary":"<p>C++23&#8217;s new facilities for handling disappointments without exceptions.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/31951","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/706"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=31951"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/31951\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=31951"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=31951"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=31951"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}