{"id":165,"date":"2009-08-31T11:28:56","date_gmt":"2009-08-31T00:28:56","guid":{"rendered":"http:\/\/blog.mozilla.org\/nnethercote\/?p=165"},"modified":"2009-08-31T15:59:00","modified_gmt":"2009-08-31T04:59:00","slug":"no-else-after-return-considered-harmful","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/nnethercote\/2009\/08\/31\/no-else-after-return-considered-harmful\/","title":{"rendered":"&#8220;No-else-after-return&#8221; considered harmful"},"content":{"rendered":"<p><strong>(Update below)<\/strong><\/p>\n<p>At the time of writing this, the<a href=\"https:\/\/developer.mozilla.org\/En\/Developer_Guide\/Coding_Style\"> Mozilla Coding Style guidelines<\/a> have this recommendation under &#8220;General C\/C++ Practices&#8221;:<\/p>\n<blockquote><p>Don&#8217;t put an else right after a return. Delete the else, it&#8217;s unnecessary and increases indentation level.<\/p><\/blockquote>\n<p>I can appreciate this in some circumstances, such as when checking for an error case early in a long function:<\/p>\n<pre>void f()\r\n{\r\n    if (errorcase())\r\n        return;\r\n\r\n    a();\r\n    b();\r\n    c();\r\n    d();\r\n}<\/pre>\n<p>But as a blanket guideline I think it&#8217;s misguided because it promotes an impure style of programming.\u00a0 And by &#8220;impure&#8221; here I mean the opposite of &#8220;pure&#8221; in <a href=\"http:\/\/en.wikipedia.org\/wiki\/Pure_function\">this<\/a> <a href=\"http:\/\/en.wikipedia.org\/wiki\/Purely_functional\">sense<\/a>, i.e. &#8220;free from side-effects and other such error-prone junk&#8221;.\u00a0 Let&#8217;s consider a simple example:\u00a0 the max() function.\u00a0 Here&#8217;s a way to write it that is quite sensible, in my opinion:<\/p>\n<pre>int max(int a, int b)\r\n{\r\n    if (a &gt; b)\r\n        return a;\r\n    else\r\n        return b;\r\n}<\/pre>\n<p>But this violates the no-else-after-return guideline.\u00a0 The Mozilla way to write this is like so:<\/p>\n<pre>int max(int a, int b)\r\n{\r\n    if (a &gt; b)\r\n        return a;\r\n    return b;\r\n}<\/pre>\n<p>(I&#8217;m not exaggerating, see <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=513379#c11\">this comment<\/a> and <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=513379#c13\">this comment<\/a> from Mozilla&#8217;s VP of Engineering and CTO respectively, about an example very similar to this.)<\/p>\n<p>Urk.\u00a0 That&#8217;s horrible.\u00a0 Any time you&#8217;re using an &#8216;if&#8217; without a corresponding &#8216;else&#8217;, you&#8217;re relying on an impure feature &#8212; you must be doing something with a side-effect in the &#8216;then&#8217; branch, or some kind of impure control flow.\u00a0 Mozilla&#8217;s coding guidelines insist that we write max(), a pure function, in an impure way.\u00a0 Also, it&#8217;s just harder to read because the two return statements have different indentation levels despite the fact that they are closely related.<\/p>\n<p>In this case there&#8217;s a way around the problem:<\/p>\n<pre>\r\n<pre>int max(int a, int b)\r\n{\r\n    return (a &gt; b ? a : b);\r\n}<\/pre>\n<p>Even though C&#8217;s if-then-else expression syntax is awful, it&#8217;s a better way to do it.<\/p>\n<p>In general, <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=513379#c21\">statements suck<\/a>, expressions rule.\u00a0 Even in a language like C\/C++ you can do something approaching functional programming by avoiding statements where possible.\u00a0 In a tiny example like max() the difference may seem trivial, but in bigger examples the difference becomes more important.\u00a0 Consider the following code from Nanojit&#8217;s register allocator which picks a register by looking at the free registers, the registers that are allowed to be used, and possibly the preferred registers.\u00a0 You don&#8217;t have to understand it closely, but it helps to know that RegisterMask is just a bitfield with one bit per register.<\/p>\n<pre>Register Assembler::registerAlloc(RegisterMask allow)\r\n{\r\n    RegAlloc &amp;regs = _allocator;\r\n    RegisterMask prefer = SavedRegs &amp; allow;\r\n    RegisterMask free = regs.free &amp; allow;\r\n\r\n    RegisterMask set = prefer;\r\n    if (set == 0) set = allow;\r\n\r\n    if (free)\r\n    {\r\n        \/\/ at least one is free\r\n        set &amp;= free;\r\n\r\n        \/\/ ok we have at least 1 free register so let's try to pick\r\n        \/\/ the best one given the profile of the instruction\r\n        if (!set)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\r\n        {\r\n            \/\/ desired register class is not free so pick first of any class\r\n            set = free;\r\n        }\r\n        NanoAssert((set &amp; allow) != 0);\r\n        Register r = nRegisterAllocFromSet(set);\r\n        regs.used |= rmask(r);\r\n        return r;\r\n    }\r\n\r\n    \/\/ ... more code here ...\r\n}<\/pre>\n<p>I find this code incredibly hard to understand.\u00a0 There are three &#8216;ifs&#8217; that lack &#8216;elses&#8217;, so it relies heavily on state updates to do its work.\u00a0 In fact, in order to understand it, I ended up rewriting it in a more pure style, by using a sequence of small refactorings:<\/p>\n<pre>Register Assembler::registerAlloc(RegisterMask allow)\r\n{\r\n    RegAlloc &amp;regs = _allocator;\r\n    RegisterMask allowedAndFree = allow &amp; regs.free;\r\n\r\n    if (allowedAndFree)\r\n    {\r\n        \/\/ At least one usable register is free -- no need to steal. \u00a0\r\n        \/\/ Pick a preferred one if possible.\r\n        RegisterMask preferredAndFree = allowedAndFree &amp; SavedRegs;\r\n        RegisterMask set = ( preferredAndFree ? preferredAndFree : allowedAndFree );\r\n        Register r = nRegisterAllocFromSet(set);\r\n        regs.used |= rmask(r);\r\n        return r;\r\n    }\r\n<pre>    \/\/ ... more code here ...\r\n}<\/pre>\n<p>There&#8217;s now only a single &#8216;if&#8217; lacking an &#8216;else&#8217;, and it turns out even that can be removed by putting the &#8220;&#8230; more code here &#8230;&#8221; part into an else branch, and then the &#8216;return r;&#8217; can be moved to the end of the function.<\/p>\n<p>The code is now comprehensible &#8212; it picks a register that is free and allowed, and preferred as well if possible.<\/p>\n<p>Part of the art of programming involves knowing when to avoid using a language feature.\u00a0 Everybody knows that &#8216;goto&#8217; is occasionally highly useful, but should be avoided whenever something less dangerous (a for-loop, a while-loop, a &#8216;break&#8217; statement) can be used.\u00a0 And everybody knows it because everybody is taught it.\u00a0 But programmers aren&#8217;t taught to avoid unnecessary side-effects&#8230; at least, I wasn&#8217;t, certainly not via examples such as those I&#8217;ve given above.\u00a0 I&#8217;ve only come to realise these things as I&#8217;ve switched several times between using C\/C++ and some pure functional languages over the years, and come to appreciate how purity helps make programs more readable and less error-prone.<\/p>\n<p>To come full circle, I&#8217;d like to see the no-else-after-return guideline removed from the Mozilla style guide, or at the very least, be qualified in a way that allows the cases I&#8217;ve argued for.\u00a0 I&#8217;d also love to see a guideline (with examples) added such as &#8220;prefer expressions to statements&#8221;.<\/p>\n<p><strong>Update:<\/strong><\/p>\n<p>(The arguments had the wrong names in the initial post, I&#8217;ve fixed them now.)<\/p>\n<p>All three versions of max() are pure, because it&#8217;s possible to combine impure pieces of code (such as an else-less if) into a pure piece of code.\u00a0 So I&#8217;ll augment my recommendation: pure code is preferable, and furthermore,<em> <\/em>given that C\/C++ makes it so easy to write impure code, it&#8217;s preferable that pure code <em>be obviously pure.<\/em> I argue that the 3rd version of max() with the ?: operator is the most obviously pure, because a ?: is pure if its operands are pure.\u00a0 In comparison, it&#8217;s harder to tell if an if-then-else is pure (although this case is still pretty easy thanks to the matching return statements).\u00a0 And an if-without-else almost never results in pure code;\u00a0 the max() example above is a rare exception.<\/p>\n<p>I also omitted a fourth formulation of max:<\/p>\n<pre>int max(int a, int b)\r\n{\r\n    int m;\r\n    if (a &gt; b)\r\n        m = a;\r\n    else\r\n        m = b;\r\n    return m;\r\n}<\/pre>\n<p>For this very simple case, such a formulation is overkill.\u00a0 But if the &#8216;then&#8217; and &#8216;else&#8217; cases are more complicated it makes more sense.\u00a0 (Furthermore, much of this discussion should be thought of in more complex cases, as these kinds of small decision can make a bigger difference then.)\u00a0 This version also doesn&#8217;t violate the no-else-after-return rule.\u00a0 So perhaps that rule isn&#8217;t as bad as I thought, if only because it&#8217;s easier to work around than I thought&#8230; but I still think rewriting the 1st version of max() into the 2nd version is a bad idea.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Update below) At the time of writing this, the Mozilla Coding Style guidelines have this recommendation under &#8220;General C\/C++ Practices&#8221;: Don&#8217;t put an else right after a return. Delete the else, it&#8217;s unnecessary and increases indentation level. I can appreciate this in some circumstances, such as when checking for an error case early in a [&hellip;]<\/p>\n","protected":false},"author":139,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[540,528,616,617],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/posts\/165"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/users\/139"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/comments?post=165"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/posts\/165\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/media?parent=165"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/categories?post=165"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nnethercote\/wp-json\/wp\/v2\/tags?post=165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}