1. 6
  1. 3

    Been dealing with some code this week that uses the “single return” pattern … by having a “goto out” jumping to the end if there’s an error higher up in the function. Makes life annoying because Go really objects to you jumping over variable declarations which means everything needs to be a var xyz at the top instead of where they would naturally be declared in scope.

    1. 5

      goto out is common in C, where it is roughly equivalent to go’s defer. Using it in go that has defer is silly of course…

    2. 2

      This isn’t talked about nearly enough, but early returns are often reason in itself to make a function out of a section of code: Ask not what the code can do in a function, but what a function can do around the code!

      For error handling, exploiting a function for early returns (or other control structure, such as a loop, just to break out of it), so that the same always happens at the end, is something I call the fallible section pattern:

      Response alwaysReply = [&](){
          TRY(fallibleFunction1());
          TRY(fallibleFunction2());
          TRY(fallibleFunction3());
          return transactionCommit();
      }();
      sendResponse(alwaysReply);
      
      1. 2

        Pascal enforced this — there was no “return” at all, you had to fall off the end of the function. I remember that it made error handling really awkward: if your function sequentially called a bunch of functions that might return errors, you generally ended up with a lot of deeply-nested IF blocks.

        1. 3
          1. 2

            Nim doesn’t enforce this but follows this tradition. If the last statement in a block is a produces a value without an assignment then it is returned, or you can set the implicit result variable.

          2. 1

            The single biggest mistake someone who knows that “single return” is silly is to use the phrase “early return”. A procedure does not return early or late, only precisely when the programmer instructs it to.

            If you want one return head to functional programming. Then use an exit monad to simulate returns or exceptions anyway.