Thou Shalt Have One Exit Point Per Subroutine -- A Monkey Cage Conundrum
secretGeek .:dot Nuts about dot Net:.
home .: about .: sign up .: sitemap .: secretGeek RSS

Thou Shalt Have One Exit Point Per Subroutine -- A Monkey Cage Conundrum

Back when I was a wee lad in Engineerin' school, fussin' with alloc and malloc and all of that hurty stuff, a particular lesson was drilled into us:

Thou Shalt Have One Exit Point Per Subroutine

This was given as gospel and we learnt it as such. It was such a fundamental principle of the coding style they drummed into us that the reasons for it were glossed over quickly -- "it make's maintenance easier".

I stuck to that principle for years -- until finally I thought about the underlying reasons, the trade-offs involved, and realised that the benefits were redundant now. The rule had become, mostly, bunk.

Yet, every time I write a subroutine that has more than one exit point, I find that other monkeys in my monkey cage jump up and down and screech and throw excrement and chatter excitedly.

The psychological aspect of their behaviour was opaque to me until recently when Phill Haack pointed out a particular monkey cage experiment.

So go and read about that monkey cage experiment now. I'll be here. Grinning demonically. Then we'll continue.

So why was that commandment so important once? And why is it no longer of such importance?

The big reason used to be around memory management.

You wanted to make sure that any allocated memory was cleaned up at the end of a routine, regardless of what other logical decisions were made during that routine.

Failure to clean up memory properly was terrible -- not just because it caused catastrophic failure. The real problem was that it caused symptoms that were very far removed from the cause itself. When you have a memory leak in a program, you can't simply read a stack trace that tells you where to go to debug the problem. You often end up having to crawl meticulously over the entire program.

In such cases you curse bitterly at any methods that have more than one exit point, because you can't check them quickly -- you instead have to analyse every last piece of logic.

We're Finally Using the Right Tools

In this age of managed-memory, that sort of memory leak is not an issue (yes, there are still ways to leak managed-memory). And better still, we have two programming constructs (in C# and others) that give the exact kind of flow control we want -- without getting in the way of the program's intent. So if you've got objects to clean up -- use 'using' or 'finally'.

Well, the surface lesson is simple. The context of a 'Best Practice' changes over time, so a best practice shouldn't be considered in absence of its context. And every practice must be revisited every once in a while, to see if the context still applies.

The deeper lesson is that monkeys can't be separated from the tortures they've undergone in the past. Maybe it's futile to try and teach old monkeys new coding paradigms. It's certainly likely to get you pelted with symian scat.

I don't like preaching -- so i'm going to stop right there. But if you're unconvinced, read up on guard clauses, and question your own beliefs a little. It's a deep deep vortex, the inner mind of the inner code monkey.

To finish that topic, here's a comment from Phil Haack that sums up my feelings well:

Get all the failure conditions out of the way at the top of the method so the body can focus on the real meat.


Ah -- one last detour...

I found a java thread on the same topic, wherein the discussion veered onto people doing things because 'that's the way they've always been'.

This lead to a discussion of driving on the right side of the road (the dominant paradigm on earth) and JosAH claimed this had deep roots in times long past:

Riding a horse on the right side of the road in the dark ages made it nearly impossible for right handed sword fighters to combat each other when they were passing each other. It's the 'peaceful' side.

to which George123 replied:

And having the steering wheel on the left side makes it easier to hit the kids in the back seat. Just thought I'll clear that up.

I am enlightened. I am at one.





'Haacked' on Thu, 30 Aug 2007 05:14:51 GMT, sez:

Well said! I think this relates to the Fail Fast school of thought too. Now I can point to this post when I defend multiple return points from a method.



'Mike Woodhouse' on Thu, 30 Aug 2007 07:06:53 GMT, sez:

I think some of the single-exit-point dogma also stemmed from the large routines that we, er, routinely used to have back in the Olden Days. These days I seem to write mostly teeny-tiny methods that might have a guard clause or two, complete with early returns, so it just doesn't seem to be an issue.

I still feel kind of naughty when I do it though...



'David Mohundro' on Thu, 30 Aug 2007 10:38:47 GMT, sez:

I was talking this exact thing yesterday. The argument FOR one exit point per subroutine was "maintenance." On the other hand, one of the primary reasons that Code Complete recommends returning early is to enhance code readability.

Like you said, with better tools for the job, the memory management reasons are no longer valid. Without those reasons, I would say that readability now equals maintainability.



'Peter' on Thu, 30 Aug 2007 11:26:49 GMT, sez:

For your information:

Horse & carriage drove on the *left*, not the right. Walking on the right was for peasants -- they needed to see what was coming, so they could jump out of the way.

In the UK, that custom persists. In France, however, they took to decapitating the upper classes, so the upper classes took to riding on the right, and then Napoleon started work on a pan-European road network.

So now you know.



'SteveJ' on Thu, 30 Aug 2007 12:11:12 GMT, sez:

I agree that long routines were more of a factor than memory management, at least when it was being drilled into my head. I still actively avoid any returns more than 5 or 6 lines into a method (ideally only the first lines are guard clauses).

Of course if I really really need to return in the middle, then I really really need to split that out into another smaller method.

What about retValue/result variables? Anyone still think that idiom has a purpose? I embraced it for awhile, but I've noticed that I've stopped using it lately.



'Simon' on Thu, 30 Aug 2007 17:57:26 GMT, sez:

You know I love your blog, but there I find a little bit of resistance having to break out of my RSS reader to read the second half of your posts. In this case, you did mention that it is continued, but sometimes you don't, and I wonder why it doesn't make sense. Anyway, this is a longhand way of say stop it; put the whole post in the RSS feed and I'll be a happy reader. Thankyou ta.



'Kev' on Thu, 30 Aug 2007 21:20:32 GMT, sez:

I'm with Simon on this one, publish the whole lot by RSS!



'lb' on Thu, 30 Aug 2007 21:47:49 GMT, sez:

@Simon and Kev -- thanks -- i do agree but i have some technical issues with putting the full text into the rss feed.

the rss standard doesn't like it if i include inline style information in the feed -- but this is something i personally enjoy doing.

hence i have to either emit invalid html for rss (bad!), or prepare a separate html file for the feed (bad! 'DRY') or have it programmatically remove inline styles (fun, but will take a little testing) or stop emiting styles (bad... i like writing styles).

help me dear abbey.

lb



'Mike Hall' on Sat, 01 Sep 2007 12:42:47 GMT, sez:

I'm a fan of single exit and try to implement in all my code. It may be more verbose, especially for smaller functions, but the maintenance argument is definitely true. It's easy to miss updating, removing or checking a return statement if there's multiple returns in a long function.

I do agree with checking the failure conditions at the top, but sometimes you simply can't do that and must wait until later on. Sure that may mean you have a long function, but sometimes you just have long functions with no need to split it up.



'nirs' on Mon, 01 Oct 2007 23:10:08 GMT, sez:

Long functions are evil - and even more with extra nesting and temporary variables needed to have only one exit point.



'casey' on Mon, 01 Oct 2007 23:29:35 GMT, sez:

With Boost smart pointers, this is a silly rule indeed, even in c++.



'GUI Junkie' on Tue, 02 Oct 2007 04:35:45 GMT, sez:

I'm completely in favor of exiting when needed. I've always programmed with multiple exit points and never ever felt any pain.

I absolutely hate the type of flow you get when people insist on having one exit point above all other considerations. Really. Just break these long functions into smaller ones and get going.

Yes I've programmed in C and No I've never had memory leaks (in three years of maintenance, we only had one bug).



'Multiple Returner' on Tue, 02 Oct 2007 07:39:37 GMT, sez:

Multiple return points begin to be painful when you have to run code coverage tools, to prove that you have tested the code thoroughly.

This is only anecdotal, but on one project where we were required to show that we had achieved at least 95% code coverage, we found that modifying the code to use a single return point at the end of each function/method made this testing substantially easier.

We also found that rewriting the code in this way resulted in much clearer code.

The only time I would encourage the use of multiple return points is for bottleneck code when you need to squeeze for performance, and returning early is vital. However, with today's compilers and the use of the 'break' keyword, I would imagine that multiple return points would still be largely unnecessary.



'Tomas' on Tue, 02 Oct 2007 08:10:06 GMT, sez:

Personally, I still think there is a case to be made for single-point returns.

Often, but not always, it makes the logic clearer by the reduction of control paths.

Secondly, not all invariants entail objects that need to be cleaned up. They can be incrementing/decrementing counters, adding/removing from lists etc. In these cases you would have to add redundancy in order to have multiple point returns.



'FeepingCreature' on Tue, 02 Oct 2007 08:27:32 GMT, sez:

By the way, D (http://digitalmars.com/d ) makes this really comfortable, with scope(exit/success/failure) allowing you to clean up a ressource right where it's allocated.
Example:
void test() {
auto foo=malloc(100);
scope(exit) free(foo);
/* much code and returns */
}

Not that I'd normally use malloc in a D program, but you get the idea :)

--FeepingCreature, rabid D fanboy



'Danno' on Tue, 02 Oct 2007 11:50:47 GMT, sez:

I agree that there's nothing wrong with multiple exit points, but single exit points are still easier to read.

Personally, I like it if I can chain it up so that a conditional is the last expression in a function, best of both worlds sorta.



'Paul Clapham' on Tue, 02 Oct 2007 13:29:01 GMT, sez:

"I agree that there's nothing wrong with multiple exit points, but single exit points are still easier to read."

That sort of thing is a large problem in our business. People just throw out unsupported assertions like that with absolutely no evidence behind them. Basically we're supposed to take somebody's personal prejudice and enshrine it as a universal law.

Well, forget it. Show us the usability studies or just shut up.



'Terr' on Tue, 02 Oct 2007 17:47:56 GMT, sez:

"Well, forget it. Show us the usability studies or just shut up."

Well, are there any usability studies for the opposite case you'd care to bring?

I believe that it depends on the nature of the function. The case for multiple-exits is particularly strong in, say, a validation function. I want to test if someone gave me a valid input. Depending on the language, I can test it for variable type, string length, regular expression tests, evaluates to a scientific notation number in the range X to Y, etc.

But if my function contract is something like "Return true if valid, false otherwise", then it makes a heck of a lot more sense to have early return-false statements than to have some sort of "isok" flag which every single subsequent test must know to skip if it's been set earlier in the routine.



'Taylor Gautier' on Wed, 03 Oct 2007 02:51:33 GMT, sez:

I blogged about this nearly 1 year ago, http://javathink.blogspot.com/2006/10/invert-your-logic-part-2-for-loops-and.html, and Haacked linked to it in April from this post: http://haacked.com/archive/2007/04/20/write-readable-code-by-making-its-intentions-clear.aspx



'Andrew Shepherd' on Mon, 08 Oct 2007 20:58:56 GMT, sez:

I bet the monkey experiment is some bogus urban myth which is useful to prove a point even though it isn't true. Same as the "Boil a frog slowly and he won't jump out" one.

At least I hope it isn't true. Who comes up with these kind of experiments? I'd be one pissed off monkey if people were trying this on me.



'lb' on Mon, 08 Oct 2007 22:10:28 GMT, sez:

yep - the frog boiling is indeed a myth!

http://www.snopes.com/critters/wild/frogboil.asp



'lb' on Mon, 08 Oct 2007 22:14:07 GMT, sez:

http://uclue.com/index.php?xq=801
after a lot of research, pinkfreud says:
"the experiment ... is almost certainly fiction"

check out this excellent query they use to find it referenced in books

http://books.google.com/books?q=monkeys+bananas+%22cold+water%22

(the aim here is to find a 'first source' -- and then if that can be debunked, the myth is busted.)

(p.s. seems i can't read my own captcha)




name


website (optional)


enter the word:
 

comment (HTML not allowed)


All viewpoints welcome. But the right to delete any post for any reason is reserved. Don't make me do it. Comments may be republished, emailed to your loved ones or printed and used as toilet paper. Who reads this legal bit anyhow?

TimeSnapper is a life analysis system that stores and plays-back your computer use. It makes timesheet recording a breeze, helps you recover lost work and shows you how to sharpen your act.

TimeSnapper won last year's Developer Competition at Larkware.com, and is used by over 10,000 people.

Articles

JSON Query Languages: 5 special purpose editors JSON Query Languages: 5 special purpose editors
What then, is b? What then, is b?
SQLike: A simple editor SQLike: A simple editor
Yet Another BizPlan Generator. Yet Another BizPlan Generator.
HOT GUIDS: A hot or not site for guids HOT GUIDS: A hot or not site for guids
How does life get better? One tiny hack at a time. How does life get better? One tiny hack at a time.
24 things to do, and 100 things *not* to do (yet) for building a MicroISV 24 things to do, and 100 things *not* to do (yet) for building a MicroISV
Venture capital won't kill Jeff Atwood, it will only make him Jeffer. Venture capital won't kill Jeff Atwood, it will only make him Jeffer.
A handy workflow image for newbie mercurial users A handy workflow image for newbie mercurial users
Fractal Feedback, a diversion into recreational programming Fractal Feedback, a diversion into recreational programming
Hump-Jumping: How the Education of Computer Science can be Saved, err, maybe. Hump-Jumping: How the Education of Computer Science can be Saved, err, maybe.
Suggested User Experience Improvements for DiffMerge Suggested User Experience Improvements for DiffMerge
SQL Style Extensions for C# SQL Style Extensions for C#
The Movie Hollywood (And My Wife) Doesn't Want You To See: Weekend at Jacko's The Movie Hollywood (And My Wife) Doesn't Want You To See: Weekend at Jacko's
Sysi: the ultimate administrators toolkit Sysi: the ultimate administrators toolkit

Archives .: secretGeek :: Complete Archives
TimeSnapper -- Automated Screenshot Journal TimeSnapper.com    
Version 3.3: true productivity boost

Next Action NextAction
Managing the top of your mind

World's Simplest Code Generator (html edition) World's Simplest Code Generator

25 steps for building a Micro-ISV 25 steps for building a Micro-ISV
3 minute guides -- babysteps in new technologies: powershell, JSON, watir, F# 3 Minute Guide Series
Universal Troubleshooting checklist Universal Troubleshooting Checklist
Top 10 SecretGeek articles Top 10 SecretGeek articles
ShinyPower (help with Powershell) ShinyPower
Now at CodePlex

Realtime CSS Editor, in a browser RealTime Online CSS Editor
Gradient Maker -- a tool for making background images that blend from one colour to another. Forget photoshop, this is the bomb. Gradient Maker


[powered by Google] 


How to be depressed How to be depressed
You are not inadequate.



Recommended Reading

The Best Software Writing I
The Business Of Software (Eric Sink)

Recommended blogs

Jeff Atwood
Joseph Cooney
Phil Haack
Scott Hanselman
Julia Lerman
Rhys Parry
Joel Pobar
OJ Reeves
Eric Sink

Aggregated Links

proggit
dzone
hacker news
dot net kicks

Human Link Machines

interesting finds
a continuous learner's weblog
arjan's world
weekly link post

LinkedIn profile
LogEnvy - event logs made sexy
ShuffleText - fuzzy search for .net
PC Smart Buys - Computer Hardware in Australia
 
home .: about .: sign up .: sitemap .: secretGeek RSS .: © Leon Bambrick 2006 .: privacy

home .: about .: sign up .: sitemap .: RSS .: © Leon Bambrick 2006 .: privacy