Hacker News new | ask | show | jobs
by eweise 1346 days ago
"For example, lots of Java devs are against early and multiple returns to the point of absurdity, while in functional languages this is idiomatic and no problem at all."

Which functional language are you talking about? Of the two functional languages I know, Elm can only have a single return statement. Scala encourages a single return.

1 comments

In a functional language technically you don’t have multiple returns, because the function is a single expression so in a way you’re right. On the other hand the actual result of the expression is determined on a leaf of the expression so you could consider it a return point

To make an example the following expression can be considered to have two returns:

    max x y =
      if x > y
      then x
      else y

The Java equivalent is

    int max(int x,int y) { 
      if (x>y) 
        return x;
      else 
        return y;
   }

Some people abhor the idea of having multiple returns in a method, and say that you should write it like

    int max(int x, int y) {
      int result;
      if (x>y) 
        result = x;
      else 
        result = y;
      return result;
    }
(Disclaimer: Contrived and buggy example as I am on mobile)
Yes this is exactly what I meant. After years of coding in Haskell and Clojure, and then going back to Java I have absolutely no problems with

    int max(int x,int y) { 
      if (x>y) 
        return x;
      else 
        return y;
   }
I just looks completely fine to me, but colleagues would complain about it in reviews and I just don't understant the problem at all. The variant with the extra result variable looks just wierd to me, and I have seen much uglier code written by people desperately avoiding early/multiple returns.
What do these languages do when you accidentally miss a branch in you decision tree? Is there any lexical or static analysis error, or does it cause a runtime error or implicit null return when you hit the actual missed condition? I think these differences in potential outcomes are what guide many of these cultural rules of thumb in different programming styles.

In imperative programming, a bunch of nested conditionals can easily have incomplete coverage of possible program states, and it can be easy to overlook problems if you have a mixture of side-effect branches and early returns. I think some people struggle with this more than others, and it can flummox them almost like goto-laden spaghetti code.

Of course, there are other areas where similar errors can occur in different languages, i.e. in exception-handling or pattern-matching constructs. There are many different coding styles which can make these control-flow structures easier or harder to debug. But, I think there can also be a lot of "cargo culting" where zombie rules of thumb continue beyond when they were really particularly helpful.

And this is likely one of those zombie rules. It's a trivial case and anyone with a semblance of programming knowledge understands what happens. You don't even need the else statement in GP's case. Meanwhile, any non-trivial case is so context-dependent you can't blindly apply rules and claim to have the best result or even just a better result from what people would come up with naturally.

The fact everything is context-dependent is the basis of all these discussions to begin with. We severely lack evidence and most rules are hearsay taken as gospel.

Cargo-culting from C where you have explicit malloc() and free(). Best practice was to have only 1 return to ensure free() was always called on everything just before the return, so you wouldn't have a memory leak if one was missing from an early return.
I was wondering where this 1 return practice originated from, but yeah, it makes sense in that context.