Hacker News new | ask | show | jobs
by rmcclellan 5237 days ago
Neither solution is great. Excessive use of return and continue is an incredibly fast way of making code completely incomprehensible.

Such complicated control flows should be treated as a major, fundamental problem. Keeping them in place will cause bugs and prevent future contributors from having confidence that their changes are correct. The problem of complicated control flow is too deep to be solved with a band-aid like this, although perhaps syntactically it looks a bit nicer. In fact, this is exactly what people did before the so-called "structured programming adepts" came around, except using gotos instead of continues. It didn't work so well back then, and it doesn't work so well now.

2 comments

It works fine as long as the early returns are for error-checking or default values. Generally, you want each function to do one thing and do it well; one very effective way to structure this is to bail out early if that one thing can't be accomplished, and then have the body of the function actually do it.

If the actual logic requires many branching paths, then usually I'd reach for a more structured solution like a chain-of-responsibility pattern, fanout, or FSM. Also, you can get pretty far with a bunch of predicate functions composed together with 'and'.

Hmmm, you have a point there, but what is your proposal to solve it in a correct way, then?

Some problems need a deeply nested control flow and arcane business rules, you have to implement that somehow, and in such a case the method I use looks like the lesser of two evils. I'd rather have some flat ecosystem of meaningful functions than one monolithic deeply nested control structure.

From time to time I like defensive programming, and when I write a function 'frob' that promises to frob something, that function first makes sure that the thing can indeed be 'frobbed', and if not, bails out. This also works well for programs that should be idempotent (although that is a whole other issue).

The way I would do it is to push the processing out to functions, too. Something like:

  verdict = get_verdict(the_thing)
  if verdict not in blessedsolutions:
      return
I'd advise against running returns onto the same line - I find it makes it harder to read, particularly when you have a lot of checks like this.
"The way I would do it is to push the processing out to functions, too."

This is indeed a good idea to isolate code away, but wouldn't alleviate a deeply nested control structure. It would make it somewhat more easier to look at, though.

"I'd advise against running returns onto the same line "

I usually follow PEP8 and place returns and continues on the next line, but the code examples I posted earlier had to be a bit condensed to conserve screen space, that's why ;-)

Sometimes your problem space is really just that complex, in which case there's not much you can do, short of writing some sort of business rules engine.