News for hackers. Stuff that matters.
Re:Using the switch(true) pattern in JavaScript by thomas_moon on Monday April 12, 2021 @11:08AM (#26780226)
The early return pattern was the most effective single piece of advice I received from a senior dev on how to make my code more readable. You end up with clearer code paths than any other pattern I have seen so far and way less indentation making things look (and probably perceived) as less complex.

Pair it with naming your complex and chained expressions and suddenly you have some seriously readable code.

So far, I have never seen a valid scenario where a switch statement is actually any better than if.

Re:Using the switch(true) pattern in JavaScript by anyonecancode on Monday April 12, 2021 @05:29PM (#26785437)
I think the early return pattern makes the most sense when it's less "logic" and more "validation." Eg in the example, the code isn't really _doing_ anything if there's no user or no first name, it's running a bunch of checks _before_ trying to do anything. Those validation checks are implemented with if/early return, but the actual pattern is more "validate first and only proceed if everything checks out."

In typed languages a lot of those checks get implemented in your actual types, but you still might have various business logic/data integrity checks you might implement in early return.

Seen in this light, this pattern's really not so much in tension with the idea of having a single return variable. It's just a way to implement the idea that invalid states should not be possible, which you accomplish in your type system when and if possible, and fall back to runtime checks for the gaps where it's not.

Re:Using the switch(true) pattern in JavaScript by jandrese on Monday April 12, 2021 @04:24PM (#26784674)
Early return can get into trouble if you're talking about a function that has a fair bit of state to unwind in the event of an error. Open filehandles, allocated memory, general cleanup stuff.

That said, I much prefer early return whenever it makes sense. In functions that do have a lot to unwind and many possible points of failure I'll pull out the old villain 'goto' and have the unwind code at the bottom of the function.

Strictly sticking to only one approach is usually a mistake. One that is repeated a lot in computer science. There are schools of thought that if everything is the same it will be easier to understand, but what happens is problems that don't exactly fit the mold end up being solved in awkward and inefficient ways. Or development gets slowed because you have to refactor your problem around the tools instead of the other way around.

Re:Using the switch(true) pattern in JavaScript by Jtsummers on Monday April 12, 2021 @05:04PM (#26785169)
> Early return can get into trouble if you're talking about a function that has a fair bit of state to unwind in the event of an error. Open filehandles, allocated memory, general cleanup stuff.

This is where Lisp's unwind-protect, finally blocks in some languages, defer in Go, and C++'s RAII pattern can come in handy. Especially if you have a healthy respect for goto and want to minimize its presence in your code for various reasons.

Re:Using the switch(true) pattern in JavaScript by golergka on Monday April 12, 2021 @06:07PM (#26785774)
`finally` introduces additional blocks, so if you have 5 different resources that you acquire as your function goes along, you end up with 5 levels of curly braces. Not very elegant.

`defer`, on the other hand, is probably the only thing I wanted to take from Go to other languages I worked with. Beautifully explicit and wonderfully useful.

Re:Using the switch(true) pattern in JavaScript by shhsshs on Monday April 12, 2021 @07:23PM (#26786387)
C#’s new syntax for `using` also helps:

Old:

    using (var file = OpenFile())
    {
        // use file
    }
New:

    using var file = OpenFile();
    // file will be disposed when it goes out of scope
Re:Using the switch(true) pattern in JavaScript by earthboundkid on Monday April 12, 2021 @07:42PM (#26786520)
> `finally` introduces additional blocks

It would be cool if someone made a way to scope variables at the function level in JavaScript instead of at the block level. I might write a transpiler for it…

Re:Using the switch(true) pattern in JavaScript by golergka on Monday April 12, 2021 @08:53PM (#26787005)
I've never considered writing a proposal for a language feature before, but after 2 minutes of googling, this actually looks completely doable:

https://github.com/tc39/ecma262/blob/master/CONTRIBUTING.md

So, impostor syndrome aside, why not? Wanna team up on that?

Re:Using the switch(true) pattern in JavaScript by earthboundkid on Tuesday April 13, 2021 @12:04PM (#26794303)
whoosh.gif
Re:Using the switch(true) pattern in JavaScript by golergka on Tuesday April 13, 2021 @02:15PM (#26796648)
Okay, it was 2am here and I must have misread your comment and lost the 'variables' part.
Re:Using the switch(true) pattern in JavaScript by jakopo87 on Tuesday April 13, 2021 @03:20AM (#26789083)
It is already possible: var makes a variable function-scoped, let/const makes a variable block-scoped. Or are you referring to something else?
Re:Using the switch(true) pattern in JavaScript by throwanem on Monday April 12, 2021 @07:27PM (#26786412)
I don't know of an equivalent in the native API, but Bluebird's "disposer" implements this in the context of promises: http://bluebirdjs.com/docs/api/disposer.html

It would be nice if there were an equivalent in the native API. You can use .finally() with chained promises, but as far as I know there's nothing comparable with async/await yet, and that's a much more comfortable syntax with which to work with promises overall.

Re:Using the switch(true) pattern in JavaScript by brundolf on Monday April 12, 2021 @02:29PM (#26783179)
Unpopular opinion: I think early-returns make code less readable if you don't put the rest of the function in an else clause. You lose visual parallelism, and suddenly instead of following a tree down to a series of leaves where every leaf terminates, you have to have the full context to know whether or not a line of code may not execute in some cases. For example:

  function foo(x) {
    if (x == null) {
      return null;
    }

    x += 2;
    return x;
  }
I can't just look at "x += 2;" and know whether or not it's conditionalized. I have to have the full context including the early-return, and then reason about the control flow from there. Whereas:

  function foo(x) {
    if (x == null) {
      return null;
    } else {
      x += 2;
      return x;
    }
  }
Here I can tell just from the else-block that this is one possibility which will execute if the other one does not, and vice-versa. Their indentation is the same, cementing their relationship. If I want to know whether this block will execute I need only look at the if()'s, not their contents.
Re:Using the switch(true) pattern in JavaScript by kbenson on Monday April 12, 2021 @03:48PM (#26784243)
I think your version isn't really as different as it seems to some. To me, the essential bit of early return is that you handle cases that eliminate the work first. That is, it's less about singular if statements separating the rest of the body of the function than it is clearly short circuiting the code as early as is clearly possible.

That is, I don't think it matters too much whether you do:

    function div(x,y) {
      if (y == null) {
        return null;
      }
      if (y == 0) {
        return null;
      }
    
      return x/y;
    }
or

    function div(x,y) {
      if (y == null) {
        return null;
      } else if (y == 0) {
        return null;
      } else {
        return x/y;
      }
    }
as they both accomplish the same major benefit of the pattern.

The real thing it's helping to avoid is accidentally creating something like this:

    function div(x,y) {
      if (y != null) {
        if (y != 0) {
          return x/y;
        } else {
          return null;
        }
      } else {
        return null;
      }
    }
which can quickly get very hard to reason about without in more complex cases.
Re:Using the switch(true) pattern in JavaScript by brundolf on Monday April 12, 2021 @03:50PM (#26784264)
You're right that both technically qualify as early-return, which is why I qualified my original statement with "if you don't put the rest of the function in an else clause".

In practice, in C-like languages, I tend to see the "else-less" version which is why I brought it up

Re:Using the switch(true) pattern in JavaScript by kbenson on Monday April 12, 2021 @08:19PM (#26786747)
If you haven't seen it, Kevlin Henney's talk about "The Forgotten Art of Structured Programming"[1] is interesting (if somewhat long in the examples later), and somewhat related. It's not specifically about return early (and a case could be made that it should or should not apply specifically to early return), but it is about if, else, return, and how they affect cognitive load when reading code.

1: https://youtu.be/SFv8Wm2HdNM

Re:Using the switch(true) pattern in JavaScript by cryptonector on Monday April 12, 2021 @03:04PM (#26783654)
On the contrary, if early returns allow you to outdent a larger portion of code then it's quite a readability win. As long as all the early return cases are bite-sized and the last case long-ish, it's a readbility win.
Re:Using the switch(true) pattern in JavaScript by jbverschoor on Monday April 12, 2021 @03:08PM (#26783719)
And certain languages allow:

return nil if n.nil?

Re:Using the switch(true) pattern in JavaScript by sneak on Monday April 12, 2021 @07:14PM (#26786323)
I really miss postfix conditionals from perl/ruby/coffeescript in all of the other languages. (Along with until/unless, which are just while! and if!.)

I asked on the go-nuts mailing list about perhaps including them in go2, but it seems many of the people who replied hate them.

Re:Using the switch(true) pattern in JavaScript by ufo on Monday April 12, 2021 @06:36PM (#26786047)
I have the same opinion. I like the early-return pattern when it's doing input validation or raising errors but for most other things I prefer how the if-else highlights that there are two possible paths that the code can take. Just because the "then" branch has a return statement doesn't mean that we should get rid of the "else".
Re:Using the switch(true) pattern in JavaScript by t-writescode on Monday April 12, 2021 @03:29PM (#26783990)
I think the bigger problem you may be experiencing, if I had to guess, code structure.

If people tend to write:

   function foo(x) {
     if (x == null) {
       return null;
     }

     // do some stuff to the code


     for(a reason) {
        // do some more stuff
        if(some detailed reason) {
          return null;
     }

     // more things
     return 7;
   }
Then the shape of the code and the "pattern" of early returns gets broken.

If you read code where all of the short-circuit, early-return logic is at the start of the function, and then all of the work is done, do you still have this opinion?

E.g.

   function foo(x) {
      if(x == 1) { return null; }
      if(x == 2) { return null; }
      if(x > 7) { return null; }

      // do things with x
      return 7;
   }
?
Re:Using the switch(true) pattern in JavaScript by brundolf on Monday April 12, 2021 @03:33PM (#26784050)
The problem is definitely much worse when returns are scattered throughout the function instead of grouped at the top, but I still prefer them to be "elsed" together (or in a switch/cond/match statement or whatever). Worth noting that in Lisp - one of the classical languages where early-returning is popular - there isn't a problem because it is done as I describe:

  (cond
    (early-return-condition early-value)
    (second-early-condition early-value2)
    ...
    (t final-else-value))
The "default case" is on the same footing as the other cases. Only in procedural languages does the control-flow get confusing if you aren't careful.
Re:Using the switch(true) pattern in JavaScript by t-writescode on Monday April 12, 2021 @03:35PM (#26784078)
If you want elses everywhere, how do you protect yourself from nesting hell? I find nesting hell to be far, far, faaaar worse for readability than any of the alternatives, and will move to the early return model to escape all that nesting.
Re:Using the switch(true) pattern in JavaScript by brundolf on Monday April 12, 2021 @03:41PM (#26784157)
I dunno, I just rarely ever find myself nesting more than two or three levels of conditionals even in extreme cases. If my logic really is that complicated, it's probably a sign it needs to be broken up anyway. And if I did need that much branching, I would want to be more explicit about it, not less.

Also - at the very least - you can mimick the "flat" early-return style and just stick some else's in there and call it a day. That's my main point; less so the actual deeper nesting

Re:Using the switch(true) pattern in JavaScript by tpoacher on Monday April 12, 2021 @03:41PM (#26784162)
I agree, but also I think this is misrepresenting the 'early return' pattern. It's more likely to be succinct and look like this instead:

    function check(x) {
        if (!test1 (x))   return false;
        if (!test2 (x))   return false;
        if (!test3 (x))   return false;
        if (!test4 (x))   return false;
        return true;
    }
In _this_ scenario, it is true that this is much more readable than:

    function check(x) {
        if (!test1 (x)) {
           return false; 
        } else if (!test2 (x)) {
           return false;
        } else if (!test3 (x)) {
           return false;
        } else if (!test4 (x)) {
           return false;
        } else {
           return true;
        }
    }
Re:Using the switch(true) pattern in JavaScript by tsimionescu on Monday April 12, 2021 @03:51PM (#26784272)
Never ever use if without curly braces. That's one of the worst ideas of C's syntax.

Your first example would still look clean like this:

  function check(x) {
      if (!test1 (x)) { return false; }
      if (!test2 (x)) { return false; }
      if (!test3 (x)) { return false; }
      if (!test4 (x)) { return false; }
      return true;
  }
And it would be much safer from stupid copy/paste errors.
Re:Using the switch(true) pattern in JavaScript by jhgb on Monday April 12, 2021 @05:53PM (#26785659)
Instead of

    function check(x) {
        if (!test1 (x))   return false;
        if (!test2 (x))   return false;
        if (!test3 (x))   return false;
        if (!test4 (x))   return false;
        return true;
    }
why wouldn't you do something along the lines of

    (every (lambda (f) (funcall f x)) (list #'test1 #'test2 #'test3 #'test4a))
or whatever is the equivalent in your preferred language?
Re:Using the switch(true) pattern in JavaScript by wvenable on Monday April 12, 2021 @06:03PM (#26785743)
The tests are rarely that simple or regular.
Re:Using the switch(true) pattern in JavaScript by jhgb on Monday April 12, 2021 @06:25PM (#26785943)
Isn't that exactly the reason to put them somewhere else?
Re:Using the switch(true) pattern in JavaScript by wvenable on Monday April 12, 2021 @06:30PM (#26785995)
No, I just mean the actual tests might be something like:

    if (user == null) return false;
    if (IsCompleted(user)) return true;
    if (action == null) return false;
    if (value < 0 || value > 100) return false;   
You're not usually just passing a single value to a bunch of "test" functions.
Re:Using the switch(true) pattern in JavaScript by jhgb on Monday April 12, 2021 @08:18PM (#26786740)
Well, the way it was written, I was assuming that conditions to be satisfied had separate named predicates (although combinators could alleviate even some of these things).
Re:Using the switch(true) pattern in JavaScript by brundolf on Monday April 12, 2021 @03:44PM (#26784191)
Worth noting that elses don't require curly braces, which are where most of the visual noise is coming from in your example:

  function check(x) {
    if (!test1 (x))      return false; 
    else if (!test2 (x)) return false;
    else if (!test3 (x)) return false;
    else if (!test4 (x)) return false;
    else                 return true;
  }
I think this is more clear than either of the above
Re:Using the switch(true) pattern in JavaScript by tpoacher on Monday April 12, 2021 @03:49PM (#26784249)
> Worth noting that elses don't require curly braces

True. I still think the first is clearer though. Either all tests pass, or they don't.

Re:Using the switch(true) pattern in JavaScript by tpoacher on Monday April 12, 2021 @03:50PM (#26784257)
(also I'd be very skeptical of such an if..else ladder. Prime target for bugs.)
Re:Using the switch(true) pattern in JavaScript by alerighi on Monday April 12, 2021 @07:10PM (#26786293)
That code is ugly anyway, something I would have wrote in middle school... why not:

    function check(x) {
        return test1(x) && test2(x) && test3(x) && test4(x);
    }
Or, since I assume is JavaScript, just:

    const check = x => test1(x) && test2(x) && test3(x) && test4(x);
Re:Using the switch(true) pattern in JavaScript by brundolf on Tuesday April 13, 2021 @12:29PM (#26794862)
Nobody would actually write this, it's just a demonstration of the pattern at hand for the sake of discussion
Re:Using the switch(true) pattern in JavaScript by wvenable on Monday April 12, 2021 @05:59PM (#26785715)
For a single condition it doesn't matter much either way for readability. But once you have a number of conditions the if/else style becomes unwieldy.

I put all my early returns at the top as these are the preconditions for the rest of the code; I don't think that's hard to understand.

Re:Using the switch(true) pattern in JavaScript by darepublic on Monday April 12, 2021 @08:17PM (#26786724)
Nit, the x is a copy so it won't change the value of x outside the function. So I would rewrite ad

const foo = x => x !== null ? x + 2 : null

Re:Using the switch(true) pattern in JavaScript by jbverschoor on Monday April 12, 2021 @03:07PM (#26783696)
Sadly, a lot of junior and medior programmers see that as a wrong pattern, and opt for a return variable.. Drives me nuts.
Re:Using the switch(true) pattern in JavaScript by speedyapoc on Monday April 12, 2021 @03:32PM (#26784037)
I recall this pattern being taught in my first year or two of my computer science degree. Emphasizing only one return statement per function, utilizing a shared return variable.

I much preferred (and still greatly prefer in industry) the pattern of exiting the function as soon as possible.

Re:Using the switch(true) pattern in JavaScript by cryptonector on Monday April 12, 2021 @04:07PM (#26784483)
It's like "goto considered harmless" -- structured code to max, to the point of unreadability. Dogmatism has drawbacks.
Re:Using the switch(true) pattern in JavaScript by jbverschoor on Monday April 12, 2021 @03:41PM (#26784160)
Same here.

Returning and throwing quickly and strict.

Re:Using the switch(true) pattern in JavaScript by joshAg on Monday April 12, 2021 @06:19PM (#26785883)
In C when you have nothing that needs cleanup, it's not the most horrible thing ever:

  int foo(thing_t \*work) {
    int ret = E_SUCCESS;

    if(work->thing == BAD_THING) {
      ret = E_BAD;
      goto exit;
    }
  
    do_some(work);
  
    if(work->thing2 == OTHER_BAD_THING) {
      LOG("whoopsies");
      ret = E_OTHER;
      goto exit;
    }
  
    ret = do_more(work);
    if (!ret) {
      LOG("lazy");
      goto exit;
    }
  
    ret = last_bit_of(work);
  
  exit:
    return ret;
  }
Re:Using the switch(true) pattern in JavaScript by kbenson on Monday April 12, 2021 @11:23PM (#26787805)
I find the safe way to program that is always to set the initial value to some error. You only set it to success at the point you succeed. Then you never have to worry about some odd goto or other break in the control glow being introduced by you or someone else that wasn't paying attention. It's also better self documentation, because then it's obvious at what point you're actually done, in the case your final work isn't aptly named "last_bit_of_work(work)", because you'll see the return variable set to E_SUCCESS immediately afterwards.
Re:Using the switch(true) pattern in JavaScript by joshAg on Monday April 12, 2021 @11:42PM (#26787908)
agreed, but some people dislike that because you have to have an E_UKNOWN or E_GENERAL or something like that in addition to more specific errors and others dislike it because now there's not something to conveniently store results from called functions in so that they can be checked for errors.
Re:Using the switch(true) pattern in JavaScript by earthboundkid on Monday April 12, 2021 @07:43PM (#26786531)
I see that as a sign that the person learned how to program in the 80s/90s when things were still in a phase of overreaction to the popularity of BASIC and GOTO. GOTO is bad, therefore return is good, and single return is best. Not actually good logic, but that was the thinking at the time.
Re:Using the switch(true) pattern in JavaScript by vsareto on Monday April 12, 2021 @03:30PM (#26784010)
They should really use both
Re:Using the switch(true) pattern in JavaScript by mekster on Monday April 12, 2021 @12:34PM (#26781483)
Unwanted conditions should be handled before handling the process in a peaceful condition.

Not sure it makes much sense to indent everything within "if" and if you forget to "else", you've just potentially hidden a bug.

Re:Using the switch(true) pattern in JavaScript by radicalriddler on Monday April 12, 2021 @07:08PM (#26786277)
I haven't written else if in javascript in years, and else is a very very rare staple in my code. Return pattern was an eye opener from a senior dev.