Remix.run Logo
SideburnsOfDoom 2 days ago

The "no early returns" rule came about because was a good rule in context, specifically C and FORTRAN code before roughly 1990. It was part of "structured programming", contemporary to "Go To Statement Considered Harmful", Dijkstra, 1968. And it became received wisdom - i.e. a rule that people follow without close examination.

For example of the rule, a function might allocate, do something and then de-allocate again at the end of the block. A second exit point makes it easy to miss that de-allocation, and so introduce memory leaks that only happen sometimes. The code is harder to reason about and the bugs harder to find.

source:

> A problem with early exit is that cleanup statements might not be executed. ... Cleanup must be done at each return site, which is brittle and can easily result in bugs.

https://en.wikipedia.org/wiki/Structured_programming#Early_r...

About 90% of us will now be thinking "but that issue doesn't apply to me at all in $ModernLang. We have GC, using (x) {} blocks, try-finally, or we have deterministic finalisation, etc."

And they're correct. In most modern languages it's fine. The "no early returns" rule does not apply to Java, TypeScript, C#, Rust, Python, etc. Because these languages specifically made early return habitable.

The meta-rule is that some rules persist past the point when they were useful. Understand what a rule is for and then you can say when it applies at all. Rules without reasons make this harder. Some rules have lasted: we typically don't use goto at all any more, just structured wrappers of it such as if-else and foreach

zahlman 2 days ago | parent [-]

> And they're correct. In most modern languages it's fine. The "no early returns" rule does not apply to Java, TypeScript, C#, Rust, Python, etc. Because these languages specifically made early return habitable.

Early return is perfectly manageable in C as long as you aren't paranoid about function inlining. You just have a wrapper that does unconditional setup, passes the acquired resources to a worker, and unconditionally cleans up. Then the worker can return whenever it likes, and you don't need any gotos either.

SideburnsOfDoom 2 days ago | parent [-]

> In C, you just have a wrapper that does unconditional setup, passes the acquired resources to a worker, and unconditionally cleans up. Then the worker can return whenever it like

Right, so you allow early return only in functions that do not have any setup and clean-up - where it's safe. Something like "pure" functions. And you describe a way to extract such functions from others.