back to article Bloody code!

It's amazing how some good practices limp on for decades beyond their expiration date. I still encounter people who insist that a method should have only one point of return - as if we're all still littering our code with GOTOs, and the concept of a "black-box" function was never invented. The way these same people go on about …

COMMENTS

This topic is closed for new posts.

Page:

  1. fluffy
    Thumb Up

    Thank you!

    You have exactly summed up why single-return code isn't necessarily a good thing. In fact, ALL religious coding practices are problematic. Having general guidelines (such as "don't use break or continue in loops") is okay, but having specific mandates (such as "NEVER use break or continue in loops") leads people to slavish devotions to practices which end up making some pieces of code look WORSE than the problems that the guidelines are trying to avoid.

    I really wish that more people would understand that rules of thumb are guidelines, and that it's okay to not have total devotion to them.

  2. Rich Turner
    Stop

    Sorry - just can't agree with you on this one.

    Multiple exit points, just like multiple exit wounds, are *DEFINITELY* things to avoid.

    Having to read through and fully comprehend every state that a given method/function can represent in order to work out just why the developer decided to jump out of one of the several (often randomly placed) exit hatches often leads to errors - some subtle, some less-so.

    Reading through a piece of code that clearly disambiguates precisely in which conditions the code will act, and where it won't, resulting in a single point of exit (at the bottom of a method where everyone expects it to happen) is *FAR* easier to understand, support and maintain.

  3. Brad Hutchings
    Unhappy

    More nuanced

    Single exit points should lead to development of easier to read code with explicit logic. That is, if you develop with the singe exit point in mind, and not try to retrofit the rule onto code that has multiple exit points. It should lead to code that allows testing of all the code. If you haven't run all lines of code in your flight system, how are you going to offer any assurance that it won't try to crash the plane? And your point about exceptions is where things get really sloppy for those who don't adhere to single exit.. If you call a function that throws exceptions, catch them and handle them. Don't let them percolate up. Talk about impossible to test code paths!!

    Finally, even strong religious proponents of no-goto, single exit points, or any other coding convention will recognize situations where carefully violating the religious edict may increase readability, maintainability, etc. and will allow that. But adherence to the rule most of the time takes lots of problems off the table. It's usually the 20th time you run into an expensive bug caused by sloppy multiple exit point coding that makes you get religious.

  4. Tuomo Stauffer
    Go

    Vey bloody code

    Agreed. It is usually a little more complicated but the same principle. Think real life, you go to room to execute several task, go through a door, sign in and start executing tasks. Any fails, you have to leave, go to door, sign out and leave. A common SIGNOUT_LEAVE block, easiest reached by goto, no if/then/else/catch/whatif/bracket/.. mess. Now, it gets a little more interesting if on each task you get something you can't take with you. Still simple because it is just a collection. Assume these things need an action when given back, still kind of simple if they can stacked/identified/... and have the reset/return method bound, i.e. just objects. Now, think they are depend on each other, order, number, property, whatever - ouch! Now you have to really think how to leave only part of tasks done. This is where I see a lot of either repeated code or a very messy ( bloody code ) when using only one way out.

    IMHO in those cases it is always(?) better to use external control to manage resources and tell it the success or failure in exit, actually I have designed systems with hundreds of services, processes and thousands of procedures where pure EXIT with action indicator was enough, the next layer cleans out your mess. So, always design for system, not for a function or process or any single entity, sooner or later you need something more complicated and you don't want to code it all over. And what if that changes again?

  5. William Donelson
    Happy

    Clean, clear and well-documented = The Answer

    As long as your code is clean, clear and well-documented (both inline documentation, as well as clear overall documentation), then it matters not how many return-points you use.

    I like my code to be clear to someone looking at it for the first time, without 20 levels of indentation and brackets, etc.

    Good, linear, carefully thought-out code means that you don't screw whichever poor bastard has to come along when you get hit by a bus!

    Cheers!

  6. Subtilior
    Paris Hilton

    Simplicity

    More important than single exit points is to keep your methods simple. With simple methods, the logic of the

    if (account == null) return;

    thing half way through is plain. If you have a method that contains pages of code, with nested if's, for's and case's, then a return statement half way through makes the method much harder to understand.

  7. Doug

    Exits should not be buried

    My only problem with multiple exits is that it is easy to bury them. I would suggest all inputs should be validated immediately at the beginning of any function and then one exit after that. Something like:

    // Function to get the account balance

    AccountDetails GetAccountDetails(account)

    {

    if (account == null) return null;

    ...

    doug

  8. Mark Fenton
    Thumb Down

    Can't agree with you

    Code should be simple and elegant.

    Yes - at the start of functions have early exits and bail outs - but then, after that having multple exit points is asking for trouble.

    Yes, the effect can be ameliorated (sp?) by the finally clause etc - but there are too many programmers out there who don't know how to use it, or use it incorrectly. And yes - outside of your agile world there are many programmers who use GOTO (although they should be taken outside and shot). Don't forget that the majority of developers use VB (gah!).

    If everyone was a skilled programmer who rights clean and elegant code - then yes, leave it upto the programmer - but this is the real world and idiots abound. Trying to explain to one person why his code failed code review due to multiple returns all over the shop and another person's code passed code review with multiple returns.....like I've said many times - trying to manage programmers is like herding cats.

    Our coding standards allow for early exits and such, but not for multiple returns once the coding has started.

  9. Kristin McKechie
    Boffin

    All things in balance

    Just as we shouldn't get religious over the concept of single exit methods, we should also not get religious about permitting multiple exits - it depends entirely on the situation, and the purpose of the module being developed which 'rule' is appropriate...

    Personally, I try to work towards minimisation of exit points solely to give myself the comfort of ensuring that I have encapsulated all possible behaviours and states within the module as I can - so that once finished I can treat that module as a black box going forward. If I have to build 'driver' modules for any piece of code to accomodate multiple potential return states, then that just makes my own life harder downstream. I don't know about others but I often cannot remember the details of a piece of code six months after I have signed off on it and started something else....

  10. Lexx Greatrex
    Black Helicopters

    Both styles can produce counter-intuitive results.

    Developers who apply the same ruleset dogmatically to every case may actually be making their code less readable in some cases.

    The correct solution is to use the format that makes your code easy to understand and easy to maintain. Different problems, different languages, different logic; right down to different levels of method complexity mean different choices.

  11. david Silver badge

    The problem was never the GOTO - -

    - - It was the Where From? Multiple exit points have the same problem - - where did the exit come from? But it's important to note that setting or testing a condition at the top and then exiting at the bottom DOESN'T SOLVE THE "Where From?" problem: the setting or testing is still in a different place from the "CONTINUE".

    Structured Programming was not originally just about GOTO and single exit points: it was about creating a program by creating a structure. WHILE and DO are simple structures to replace generic GOTO commands, but then you have to do the same with the rest of your program: replace ad-hoc constructs with generic structures.

    Anyway, back to the subject, all structured programming is an attempt to avoid certain programming evils, but that does not mean that unstructured code is the evil itself. And although the restriction is expressed as a restriction on functions, back then people knew what he was really thinking about. What he was really thinking about, and what people knew about then, was that it is possible to write code where the return point is not always the same (and is not the same as the entry point). Any standard language with functions has already solved that problem: all normal functions have only one exit, leading only back to the call point, however many "return" statements you put in.

    However, you can still see the original problem if you are dealing with exceptions, particularly in a multi-threaded program.

  12. Steve Browne
    Flame

    Multiple exits

    I have generally found multiple exits to be the result of poor programming. In some circumstances, an early departure, out of an array scan loop for instance, is required once the wanted item is located. As these scans tend to be quite short and only exit to teh end of the loop, they are easier to get along with.

    Early departures from block structured procedures are quite difficult to comprehend unless adequately commented, but who does that ? If they cant be bothered to structure code reasonably, they are unlikely to put comments in! If your control structures are becoming too complex, eg indentation is getting halfway across the screen, the time has come to refactor.

    I have been programming for 30 years and have rarely come across the need to have multiple exit points. Structured programming was a very useful guide to designing program logic, and should not be dismissed so readily.

    The real problem is the proliferation of C attitudes. C is a truly awful language, with overly complex definitions and very little type safety and no default error handling. How it ever came to such prominence is a mystery. if they hadnt used zero terminated strings, there woudl be no such thing as a buffer overflow as every string would have a length associated with it which can be checked by the compiler.

    Having moved on to object oriented styles, I would have thought the single exit point is now even easier to use, with a proliferation of short procedures implementing the logic.

    Sorry, I think the use of multiple exits is useful as a guide to the level of incompetence of the coder. Easy maintenance is far more important than developer short cuts.

  13. Anonymous Coward
    Thumb Up

    Thank you!

    It's been a PITA in one of my previous job that my boss insisted on single exit points.

    Seriously, though, it flies in the face of the convention that (in many cases) it's a good idea to check the validity of the parameters passed first before starting on any real processing. I got a NULL pointer? Bail out immediately!

    If you insist on single exit points, you can't ever use exceptions either. That is, you can't throw them, but you must catch them all, in every function, just to avoid that there might be an exit point lurking there. (This may not be what the author is thinking, but that's what I'm thinking - there is not much of a difference between popping a stack frame because an exception was thrown, or doing so because of a return statement).

    Incidentally, we in the C++ world can avoid resource leaks by freeing resources in the destructor of a stack variable. Wherever you exit, once the stack frame gets popped, the resources are freed (same principle as std::auto_ptr).

  14. foxyshadis

    Catching exceptions

    "If you call a function that throws exceptions, catch them and handle them. Don't let them percolate up."

    This is more subtle but arguably even more pernicious than single-exit. Catching every exception whether it makes sense or not is a ticket to design problems. There are many exceptions that the caller doesn't actually know how to handle in all situations (whether the designer knows it or not), and the caller's parent(s) should be the one to deal with that particular exception. Catching every exception but only taking care of the ones you know about is easily just as horrible as Basic's On Error Resume Next. You will end up inadvertently swallowing something the parent should see, or performing an action that isn't called for.

    What are you going to do in that case? Copy the exception, set up a labyrinth of if/else, and then rethrow it at the end? Convert it into a return code somehow, even if it's completely unexpected?

    That's what happens when you fit old dogma onto new domains without logically thinking about whether it still fits. (Not that I consider fully exception-driven programming to be saner.)

    To others: Yes, the laundry list of assertions at the beginning of the function is the best imho. I don't care about identifying other because hey, my IDE highlights return statements in big bold brown letters, and not using a syntax highlighting editor is a crime.

  15. W.A. ten Brink
    Stop

    I disagree! Partly...

    Well, I must say that you do bring up a good point here. However, the use of multiple returns/exits can make code less readable when used in the wrong way. I have seen how it has been misused to jump out of a method in a dozen different places and even in multi-level for-loops with all kinds if conditions inside. Something like:

    if (apple==null) { for (I=0; i < 10; i++) { if (pear==null) { return; } ... More code, more returns...

    Problem is, returns can be useful when used properly. GOTO can also be very useful if used properly. Same is true for things like "break" and "continue" for loops. They all have their purpose if used properly. But in general people are NOT using these in the proper way, thus code becomes less readable. A very experienced programmer should be able to use these correctly but then again, they have enough experience to know about all alternative methods and are likely to prefer the other solutions. Inexperienced programmers are likely to make mistakes by overusing these methods, thus code becomes too complicated.

    It's fun, though. I have nearly 20 years of experience in programming and I tend to write a lot less code than colleagues of mine who are less experienced. I see them struggling to find items in lists or for validating user input. They do in 30 lines the same things that I do in 10 lines because they tend to over complicate the problem.

    But I agree, the following is very complicated:

    if (account != null)

    { // 20 lines of code

    // (that are totally irrelevant if account is null)

    // later...

    }

    // and out we pop

    So how would I do this?

    if (account != null) call_subfunction;

    And of course define the subfunction that handles the required actions. And if you have a well-made design, you don't ever need multiple returns

  16. Anonymous Coward
    Anonymous Coward

    @Fluffy

    I'm with Fluffy on this one, anything set in stone is a bad thing. I think we all have our little quirks and no amount of standards is going to change our own style. I like to have a single point of exit but if it makes the code look ugly and unreadable then I'll have multiple points. In my case it's just a preference nothing more and isn't based on anything. Having said that I believe in flexibilty there is always an exception to break the rule and the one thing I cannot bear is code with

    if <condition> {

    }

    instead of

    if <condition>

    {

    }

    HTF can anybody line up the squiggly brackets in the former?

  17. Chris Rimmer

    Re: More nuanced

    "And your point about exceptions is where things get really sloppy for those who don't adhere to single exit.. If you call a function that throws exceptions, catch them and handle them. Don't let them percolate up. Talk about impossible to test code paths!!"

    I don't think that catching all exceptions from every function is the right thing to do normally. Exceptions are designed to convey information from the place where the details of an exceptional condition are known but the appropriate response is not known to the place where the details of the condition would not otherwise be known but a sensible decision can be made about the appropriate response. Otherwise you may as well not use exceptions at all, and just return a value from the function.

    If you have a networking library, and it detects deep down in its implementation that a cable has been disconnected, it _should_ throw an exception, and that exception should not be caught by the top level of the library. It should be caught by the application code which can decide whether to exit with a message and an error status (quick hacky program), to display a dialogue box (interactive GUI program), to generate some suitable HTML (web servlet), or some other response appropriate to the type of application.

    For general-purpose programming, rather than the specialised area of safety-critical systems (about which I know little), I tend to agree with the author and some of the comments - clarity is the most important thing. Functions should be written so that they can be understood in their entirety, in which case the structured programming techniques are much less relevant. I personally find the "bail out early" style to be much clearer than the "if (still_no_errors)" style. In my experience, it is much more important to get the overall structure of the program right than the structure at the function level.

  18. Mark Rendle
    Heart

    Completely agree

    Clean, maintainable code is one of my hobby-horses at the moment, as we complete the final point release of many years' worth of old and largely impenetrable code and start again in C#. I'm compiling a document of best practices, and single exit points are NOT in it.

    Striving to make all methods fit on a single page is far more important, and that's often easier to achieve if you do have multiple exit points. If you do achieve it, then you can see all the exit points without scrolling. And when you have a function which returns null or -1 to indicate no value, it's much easier to understand:

    public int GetSomething()

    {

    foreach(something)

    if(something)

    return something;

    return -1;

    }

    instead of

    public int GetSomething()

    {

    int retval = -1;

    foreach(something)

    if(something)

    {

    retval = something;

    break;

    }

    return retval;

    }

    The second example is longer, less easy to understand, and includes a break statement which almost certainly violates the same imaginary principle that gives rise to the single exit point myth.

  19. shameek
    IT Angle

    Not a zealot

    Just to add my thoughts on the subject, I agree that sometimes it can be advantageous to have multiple exit points. However for commerial grade software, a single exit point is one "best practise" that has simplified my maintainance headaches. If you look in isolation at this practice, it does seem strict, however over the project lifecycle, it does simplify, requirements, design, development, testing and maintainance. If your in the fortunate position where your dont have other people updating your code, I dont believe it matters - apart from a personal style perspective. Working in a team, does require more discipline and this is certainly one that will help you and your team long term. The best analogy for your proposal is the film "Next" where the character can see 2 minutes into the future and uses this ability to check multiple paths. If your team has this ability then cool - go with it, for mere mortals keep it simple sweetie. Remember software engineering is a science and the fundimentals help to deliver robust, maintainable, efficient code.

  20. Tom Hobbs
    Thumb Down

    Flawed approach

    I can't agree with this article either. The easiest methods to read are the ones that are shortest and clearest. So the example;

    <code>

    if (account != null)

    { // 20 lines of code

    // (that are totally irrelevant if account is null)

    // later...

    }

    // and out we pop

    </code>

    is actually a bad one. My rule of thumb is that a method shouldn't be longer than the height of the window it's displayed in, but I would say that even a 20-something line method is probably too long.

    Also if you have a method with "excessive nesting of "if..else" " then I'd also say that such a method would be (more) difficult to read than a series of methods each of which dealt with only one condition no matter the number of exit points.

    It should be refactored to remove the excessive branching regardless of how many return points there are.

    In my experience, once your methods are of a suitable length and simple (which is a personal quantification) you're likely to find you have single return points anyway.

    You're right about exceptions though. They're dangerous and overused. They should only be used for, er, exceptional cases and are vastly overused by all and sundry.

  21. Anonymous Coward
    Anonymous Coward

    Black and white

    Those who argue black and white always end up looking like idiots. Multiple exit points are one of those things that can screw up the comprehension of your code. As long as your aware of this and code cleanly it doesn't really matter.

  22. Robert Grant

    Excluded middle

    "sort out the thinkers from the believers"

    You can be both :)

  23. John Wilson
    Flame

    Re: Simplicity

    If you have a method with pages of code, with nested if's else's and case's, you have bigger problems to worry about than whether or not there's a single exit point.

    The simple fact is, if you are programming in C++, or any modern programming language, the chances are that your method does not necessarily have a single exit point. What, for example is the standard behaivour of "new" if there's no more heap available.

    And as for "More nuianced", that is an excellent description of how not to deal with exception. Exceptions are supposed to "percolate up". You deal with the exceptions you are able to properly deal with at the time, not every last one that can occur. Exceptions have been around for a very long time now, but I am constantly stunned how many people still don't understand their use!

  24. Ashley Moran
    Thumb Down

    Yes, it does create implicit else clauses

    And this means your methods are handling too much behaviour. If you feel the need to have several return points, I suggest you look at the OO modelling in your application, which probably has over-complicated classes that need breaking down.

  25. Rich Silver badge
    Flame

    BOLLOCKS

    God, this makes me seethe!

    Use of multiple exit points is sloppy. Simple. It shows lack of coding discipline and/or clarity of thinking in how the code is structured.

    "...I'm not quite sure what's going to happen next, so I'll just bail out here and hope that what I think up in a bit will do the job".

    To address some of the points you made...

    1/ (I paraphrase) "...use the "finally" block". Well, in all my years of writing code, I've never come across a "finally" block in C! So you can cut that rubbish about "purists take note". Even the sloppiest C coder (and my god, I've knows a few in my time) wouldn't be able to use "finally". I wonder how you would survive if taken away from your cuddly warm fuzzy java or "Visual Basic" whatever you use?

    2/ "Multiple exit points make code harder to refactor ....Yes, because simpler, clearer code is always harder to maintain". Ah, do I sense a tad of sarcasm here? Well, you've obviously had an easy ride and not had to maintain some of the code I've had to over the years. I bet you're also one of those "code is self documenting" (read: "I can't be arsed to comment it") people as well, aren't you? I could write for hours on that particular topic!

    3/ "...exceptions bugger-up your execution paths anyway". Of course they do, that's why they're "exceptions". But you're missing the point. Exceptions should NOT be used as a program flow control; they are relatively expensive and guess what - they mess up the program flow! They should be used in "oh shit - this should never happen!" cases, in which case your code is shot to pieces anyway! If you are using exceptions to control program flow then you need to go back to school. And, again, as far as I know C still doesn't support exceptions.

    So in case you've not worked it out already, I think you're taking rubbish. Multiple exit points DO make code more difficult to read, they DO cause resource leaks. They DO cause things not to happen when they should (because you missed the cunning hidden "return" a few lines previously in the code that you are not at all familiar with, but you're trying to maintain). They DO introduce bugs. They ARE bloody annoying!

    And just to throw an idea into the pot - how many coding languages do you know that allow you to define functions with multiple entry points (ignoring abuse of "goto")? No - I can't think of any either. I wonder why that is?

  26. Anonymous Coward
    Alert

    Try this...

    In a paternal way I'd like to say that, as a young whippersnapper coder in the early 90's I had the same opinions. Even 15 years ago single exit points looked outdated to me. Since then I have been involved in many major C, C++, Objective C etc etc projects, some projects with up to 1,000 staff accross 3 continents, and my atitude has now changed.

    Quite simply, coding needs discipline, and although to a large extent self-discipline is king (you make your own rules, but stick to them - PSP method etc) other people need to make changes.

    And the case for single return points is simple and basic. If someone else needs to make changes to the function, they can add pre- and, crucially, POST- processing adjustments within the original function just before the function returns, without having to enter the same code 3 or 4 times for 3 or 4 return points.

    And with the adoption of risk-based testing models, it's easier to make the case for writing a minimum of new unit and system tests when it's clear how the logical execution path has been altered.

    Furthermore, in my experience, people who adhere to the principle of single return points write cleaner code that is easier to maintain, because they are encouraged to view each function as a logical sequence of operations with one start and one finish point.

    And does this make a real-world difference - hell yes. Telecoms software is riddled with FSMs, each function representing a state change action, state entry code etc etc and the number of times I've seen projects where additional actions need to be appended to the existing actions in legacy code is untrue. Military projects I've worked on with highly complex mathematics can still be maintained by guys without a degree in physics because the execution path is clear, then maths segments don't need touching if you're making a simple non-maths change.

    Father

  27. Tim

    buried exits

    Pretty much what others have said here.

    Don't have a problem with multiple exits if the code is clear, but if it's a nested munge mess and a dozen exits buried within, it's very hard to understand.

    However, rewriting the code into simple clear methods rather than a nested mess would be preferable to just slapping in a state and single exit.

    The result however would likely be that you have single exits anyway in a set of small simple methods.

    Only time these days I tend to use multiple exits is where there are parameter checks at the top that just return before the method has started. Although if it's due to the method being called incorrectly I'd use exceptions in that case.

    Of course then there is the issue of buried exceptions, or exceptions within nested code, caught in the outer code, then rethrown or turned into a regular exit hiding the exception, and other such mess, and whether these are good or bad.

    Multiple exits also complicates the situation if clean up code is required if an exit returns failure but isn't thrown as an exception. At least languages with a 'finally' concept make this less of an issue. Better code design helps too though.

  28. The Other Steve
    Coat

    Death to all extremists!

    Like all code constructs, multiple exit points are sometimes appropriate, and sometimes not.

    If it improves readability and maintainability (closely related), then go ahead and use them.

    On the other hand, if you feel uncomfortable with them, feel free to do it your way. A good coder should be competent to deal with either approach at implementation or maintenance. OTOH I've seen some truly awful constructs result from peoples attempts to avoid them just on the grounds that someone told them MEPs were 'A Bad Thing'.

    If the methodology zealots would spend less time worrying about arbitrary rules and more time worrying about clarity the software world would be a nicer place altogether.

    Hell, I've even used goto from time to time, and if that makes your blood boil, consider that all your structured exception handling is actually just goto with a fancy name.

    Good code is code that has clarity of intention, there are many ways of achieving this, but excluding some constructs because some ivory tower language facist once decided that they didn't like them, or more likely because some slashdot weenie told you so, limits your flexibility of approach. The more options you leave yourself, the more likely you are to be able to turn out an aesthetically pleasing bit of code.

  29. Anonymous Coward
    Pirate

    It's Like Pirates Of The Caribbean

    You know, the bits where someone breaks the Pirate's Code and someone else has to say "them's not really rules, them's more like guidelines, arrrr".

    Even the most ardent code-style Nazi (of either persuasion) would have to say that code littered with exit points looks like a dog's dinner. Conversely code where the author has bent over backwards to squeeze everything through a single exit point looks pretty crappy too. I've been writing C and C++ for over 20 years and of course I've seen plenty of examples of both.

    I do a lot of multithreaded stuff and one of the reasons single exit points can be A Good Thing is when you have a mutex-protected block in C - it means you can easily find the points where you lock and unlock it, knowing that you haven't bailed out anywhere in between and left it unlocked. Of course you can explicitly unlock before every exit, but that gets a bit cut-and-pastey after a while, plus there's always the possibility of a bug fixer or maintainer coming along after you and adding another exit without cleaning up.

    Nowadays in C++ we tend to hold locks and other such temporary resources items in lightweight "auto" container objects on the stack, so in that case you can bail out pretty much where you want to in a method, safe in the knowledge that your resources get destroyed safely for you.

    This approach is item 13 in Scott Meyers' excellent "Effective C++". He is proposing this idea for a number of reasons, multiple exit points being one of them.

    One final thing I would like to borrow from the world of pirates is the bit where you get to make people walk the plank. I could definitely spice up our code reviews with a cutlass, a plank and some shark-infested water.

    Yo ho ho and all that.

  30. Ian
    Stop

    A challenge

    If (x==null) then return as the first line is only more understandable than if(x!=null) version if you do not follow the standard of a single exit point.

    I use single exit point because when I return to maintain the code I do not have to follow the whole method inorder to determine the path through it. With a single exit point you always know where the code is going.

    If your single exit point code is not easy to follow then the implemtation of the algorithym is bad.

    I will put down a chanllenge, provide ANY NONE TRIVIAL multi exit code and I will refactor to single exit point and make it simplier and easier to maintain. Of cause because of the dificulties with Multi exit point you may have to explain what it does but then that only proves the point :)

  31. Steve Browne
    Thumb Up

    @Rich

    PL/1 and its derivatives can have multiple Entry points. it has Entry variables too, so they can be redefined dynamically. Rexx can have functions invoked as procedures, so sometimes it will return a value and some times it wont, so it has to have multiple exit points. With some interesting label positioning, it is possible to execute the "Then" clause and the "Else" clause of a single "if" statement, again an exit point is introduced, that doesnt actually exit but serves to confuse the hell out of anyone unsure of what they are doing.

    If ValidData()

    Then

    Return

    ValidData:

    /* do whatever validation here */

    Return (True | False)

    Else

    /* Invalid data appears here */

    Effectively a procedure is created inline, called from the IF statement, so the return is back to the IF statement, the THEN clause is redundant, so just needs a Return or null statement and the else can be executed if required.

    Cobol had the infamous "GoTo Depending On", which went somewhere as a result of a variable condition. There was the "Alter Paragraph to Proceed to" thing as well, which changed the target address of a GOTO statement. Self modifying code was considered harmful as a result of this. I have used all of these things in code and watched the horror on people faces as they tried to work with it.

  32. Julian

    I enjoy being an extremist

    I can't imagine how much multi-threaded coding involving mutexes the author has done but my guess is less than many. You can't exit at an arbitrary point when you have a broken invariants. Resource acquisition is ordered and you break the invariants protected by the mutexes one at a time: subsequently you must patch them one at a time. If you are going to release resources in the proper order, then you may as well have a controlled exit and prove to your poor successor that they have some hope of proving the invariants are maintained at the end of the function (i.e. at every return you have introduced), avoiding deadlocks and getting home before midnight.

    I have yet to meet a finally clause that is able to work out which part of which data structures have been altered and fix each of them before returning: merely releasing the mutexes and freeing memory and hoping for the best doesn't work. This is true of all programs where functions join more than one related resource, but mutlthreaded ones just make it obvious.

  33. Graham Bartlett

    Exception considered harmful...

    Oh joy, someone else who believes "try/except/finally" is the silver bullet for all ills.

    Exceptions are simply another way of writing GOTO. If you disagree, riddle me this: what other instruction forces execution to jump to an arbitrary location in code with no return path...?

    This isn't necessarily a bad thing, but as other people have said, the problem is knowing where you came from, and what happened when you were in there. Suppose your pseudocode looks something like:-

    * Create an array of handles

    * Get a load of handles to resources, and put them in the array

    * Create an array for intermediate data

    * Do some processing based on the resource data, using the intermediate array

    * Create another array of handles

    * Get a load of handles to resources, and put them in this array

    * Store processing results in the resources from these handles

    * Free handles and delete arrays

    Now add an exception for "out of memory" covering this entire section of code. What do you clean up in the exception handler? If the arrays are global then great, but if the arrays have local scope (and the intermediate array almost certainly should, if you're competent) then you're screwed - you can't get at the stuff you need to clean up, so you get memory and handle leaks. The better answer is that you nest your code so that each allocation has an associated clean-up operation. That way you have maintainable and reliable code - you know *where* the clean-up is happening, and you know the clean-up *is* happening. You can still use exceptions to handle failure if you want, but each "allocate" operation (be it memory, resource handles or whatever) needs its own exception handler to do the targetted clean-up that's required.

    The key point now is that since clean-up has to happen regardless of success or failure, a single point of exit usually gives you more efficient and maintainable code, because you only do the clean-up in one place. Et voila!

    Sure, there might be circumstances where clean-up requires some separate return path. But usually you're looking at a maximum of two return paths then, for success or failure.

    I've seen quite a few people who are great believers in "try/except" solving everything. Almost always, they're Windows programmers who've never had to handle errors properly. Their attitude is that when things go wrong, the program crashes, Windows cleans up memory when the program dies, and the user launches their program again. Great. Except that when you transplant this attitude to embedded apps (mobile phones, for example), you don't have Windows cleaning up after you. Best case, you get memory leaks - worst case, you get memory stomps and CPU exceptions. And this simply comes down to sloppy coding practises which are mitigated by the defense-in-depth which Windows (or any other PC OS) provides.

    An embedded software programmer knows better - through bitter experience, they know that if it can go wrong, it will go wrong. If it can go wrong, you'll have some error indication to let you know how it went wrong, so if there's an error indication available you *always* check it. Failure to check errors and do appropriate clean-up is the classic sign of a Windows programmer, reinforced by all Windows tutorial books which ignore the error returns from functions.

  34. Anonymous Coward
    Anonymous Coward

    @Challenge

    The lookupnum function has multiple exit points. I'd like to see your single exit point version.

    ; Get table value

    movlw 0x0F ; move b'00001111' to W

    andwf key,0 ; AND with key to get index into W

    call lookupnum ; lookup value

    movwf num

    .

    .

    .

    lookupnum:

    andwl 0x0F ; just make sure W < 16

    addwf PCL,1 ; add index to program counter

    retlw 0x3C

    retlw 0x3D

    retlw 0x3E

    retlw 0x3F

    retlw 0x40

    retlw 0x41

    retlw 0x42

    retlw 0x43

    retlw 0x44

    retlw 0x45

    retlw 0x46

    retlw 0x47

    retlw 0x48

    retlw 0x49

    retlw 0x4A

    retlw 0x4B

  35. T. O'Hara
    Dead Vulture

    As an outsider...

    who mainly designs electronic circuits but often writes drivers I prefer single exit points and I'd like to point out that the following argument:

    if (account == null) return;

    at the top of a method is much clearer, than:

    if (account != null)

    { // 20 lines of code

    // (that are totally irrelevant if account is null)

    // later...

    }

    // and out we pop

    is a bit pathetic. The second if statement clearly encompassed between braces does include completely irrelevant code if the account is not empty. For me that's part of the purpose of braces. If the account is not empty skip that lot and find the single exit point at the bottom where it belongs.

    No-one of any intelligence can argue that example 4 in any way strengthens the case for multiple exit points.

    I also find that all of the points raised have no basis in logic and are only an opinion. As far as I can see that's the problem with software engineers, too much opinion and no logic just like Matt Stephens.

  36. liar
    Stop

    @Chris W

    Let me check I understand your example function;

    You pass in a number 0 <= x < 16 and return a given value, is this the case?

    (Firstly, and as an aside, playing directly with pc in this way is generally a bad idea as it stuffs up pipelining and will usually force a flush of the pipe, and in bad cases a flush of the cache, depending on which processor you are using. It's also a pain to port as you can be caught if the pipeline length changes.).

    In your specific case this function is completely trivial and actually is just add 0x3C to W, so that's your single exit point in that case.

    In the case that you want some less mathematically predictable values for each entry then this is just a look up table. Most processors let you load from an offset from a base address in one or two instructions, so do that.

    In neither case should you actually need a function at all. Let alone a 'clever' on which messes directly with pc.

    Bah.

  37. Steve B

    Reinventing the wheel time after time.

    In the 70s I was told by an IBM employee that no IBM routine was allowed to be more than one page long as they couldn't be trusted to continue on to page 2 safely.

    My company decided to use a high level language (and programmers) to write the OS as it meant more people could participate. They actually found that in reality it meant even more mistakes as poor programmers are poor programmers whatever the language. It only took off after a suitable core of excellent programmers was built. One day Ms will reach that stage.

    These later "rules" are only rules to protect us against the worst all the time, both of programmers and compilers. I have lost count of the times I looked at the code generated by a compiler and had to rewrite it in assembler.

  38. Bruno Girin

    Single vs Multiple exit points

    As ever when writing software, the problem is not whether you use single or multiple exit points, the problem is in writing clear and maintainable code. The most important sentence in your article is this one: "If in doubt, go for the simpler, more expressive option which best communicates what the code means." Exactly!

    Having said this, guidelines like "single exit point" are good because once you have a team of programmers (team = more than 1), or even if you're on your own, guidelines will ensure that you have consistency in code. But guidelines are not set in stone, they can and should be broken if breaking them helps the overall goal of making your code simpler and easier to understand and maintain. In fact, in a previous job, I went about writing coding guidelines for the team I was working in and it started with "rule 0" that went something like this: "the aim of the guidelines are to make code simple, consistent, easier to understand and maintain; if you have a situation where guidelines interfere with this goal, you can ignore the guidelines but you have to document why you ignored them."

    To come back to single exit point or not, I apply neither of them, I tend to use a 2 exit points approach: start with checking for pre-conditions, if any of them are not met, exit immediately as you can't perform the function adequately, that's exit point #1; then have the body of the function with no exit point followed by clean-up / post-condition check code with a single exit point (#2). If the logic of my function shows that I have a natural exit point half way through, it usuallly means that the function I'm writing is actually trying to do two jobs at the same time and should be split.

    Exceptions are just that: exceptions, that is conditions that should not happen. Therefore they bypass normal program flow and are allowed to do so. You should always catch and deal with the exceptions your code can deal with but let the other ones percolate up until they are caught by some code that can deal with them or a generic exception catching block at the top of the call tree. And the 'finally' block is here to clean up when your normal program flow has been bypassed by an exception, whether it was handled or not. Using it to clean up when you have multiple exit points is sloppy and makes your code more difficult to understand.

  39. A J Stiles

    Multiple Exit Points

    Sometimes, multiple exit points are bad. Other times, the nested if statements through which one has to jump in order to work out what is going on (usually compounded by testing the wrong condition first) are worse.

    The bad example above wouldn't be so bad if it were rewritten as

    if (account == null) {

    // quickly deal with null account

    }

    else {

    // very long section of code for

    // dealing with non-null account

    };

    Except, of course, it's human nature to test for things in the order you think of them.

    What it all comes down to is The Last Rule:

    When, not if, but when you have to break one or more of the preceding rules, be sure to do so *good and hard*.

  40. Anonymous Coward
    Flame

    Code Nazis Must Die!

    Some poster writes:

    "As far as I can see that's the problem with software engineers, too much opinion and no logic"

    Rahgnagna...splutter...

    Insofar as "logic" is totally useless when discussing code structure issues (as opposed to code meaning issues) here's my "opinion":

    _Yes_ to multiple exit points from methods if:

    1) The methods are kept small (less than half a page), as they should. Anyone who brings "multiple pages of nested code" into the discussion is out of line (where are your code metrics, dude?)

    2) The method postcondition can be proven true (better yet, trivially true) at the exit point; if need be, add an assertion just before the return. Do you hear, "I enjoy being an extremist"?

    3) The stylistic result "looks good". I dislike returns from inside loops, but have no problem with returns from some intermediary check in a method.

    Anyone who answers in this thread with contrived "but what if", "multithreading and resources LOL" and "ZOMG exceptions!!" examples should be ridden out of town on a rail.

  41. Anonymous Coward
    Dead Vulture

    Why early breaking is better ?

    Well i dont know about you but lets say I have a collection of items (Lets use people) that sums about 1 Million and you have a search function that takes a single Argument ... and returns the persons ID reference.

    foreach (Person EachPerson in Persons) {

    if (EachPerson.Name== SearchName)

    return Person.ID;

    }

    return -1; // In case we don't find anything

    Now if you want to go ahead and search through all 1 Million persons then please feel free ... "Think outside the box" ... if you would rather follow rules ... maybe go programme for the Vole.

  42. Anonymous Coward
    Anonymous Coward

    @liar

    It is true that in this case simply adding a constant will give the desired result and I realised after posting that the example was flawed in this respect such is trying to get something out while thinking of lunch. Yes, it is a lookup table, however let's assume that the return values are not a simple addition. The option to load from a base address is not available to all processors so the challenge has not been completed after all it was you who mentioned portability.

  43. Curt Eckhart
    Thumb Down

    Disagree

    In my 25 years of experience, code with multiple exit points usually demonstrates bad thinking about the solution. In my opinion such passages stand out as prime candidates for refactoring or rewriting altogether.

    There is one situation where I could understand how code gets like this even in the hands of competent people. That would be where the code has been enhanced or patched many times and each enhancement has been isolated in an attempt to minimize the impact on tried and tested code.

    Nevertheless, when this situation is detected, I return to my first assertion; Such convoluted methods should be top of the list when the time finally comes to rewrite.

  44. Wolf
    Thumb Up

    KISS forever and always...

    Keep It Simple Stupid.

    Words to live by... :)

    I'm with the article's author on this one. My functions tend to have 2 (or possibly 3) major divisions:

    1) Check parameters and exit immediately if any parameter is out of bounds.

    2) Acquire resources and if not available release resources already acquired and exit immediately

    3) Do the function, clean up and exit (single exit point).

    So I fall in the multiple exit point camp. I also firmly believe in coding like I have an appointment with a Mack truck tomorrow--ie making sure somebody else (of minimal skill level) has at least a chance of following my code should I meet said truck in a dark alley.

    Other guidelines:

    1) A good comment/code ratio is 75% comment /25% code, heavy on the "why".

    2) Loops are evil. Long loops are evil on steroids. So make the code in the loop a sub/function, keep the loop to 5 lines or less if you can.

    3) Clever code is (usually) stupid. Better a small loss of efficiency for a big gain in clarity than a small gain in efficiency for a large loss of clarity.

    4) "Elegant" does not mean "convoluted". A straight line is the easiest to follow.

    5) Take advantage of color-coding and code-folding IDEs. They're God's gift to wonderful.

    Oh, and yes I'm a apps programmer not an embedded OS one. I have the good fortune of large amounts of RAM, high-level languages that handle memory for me, and a lack of gratuitous syntax. I'd be an idiot not to use those resources to make my apps maintainable.

    YMMV, of course.

  45. Rich Silver badge

    Challenge

    "The lookupnum function has multiple exit points. I'd like to see your single exit point version....."

    I'm not familiar with the assembler you have presented, but it's pretty obvious that all you have to do is replace the line...

    addwf PCL,1 ; add index to program counter

    ...and it's horrible list of "returns" with an appropriate line loading a value from an array of values and then a single "return" returning that value.

    I may have missed some subtlety of your code because as I say, I'm not familiar with the particular assembler, but the basic idea is obvious and I'm amazed that you would think to code it in the way you have.

  46. Juha-Matti Myllylä
    Alien

    @challenge

    Hi,

    Here's one simple pseudo-code challenge.

    //==================================================

    // Finds object from a universe.

    // Return: Coordinate of object if object was found.

    // If object is not found RL_NOT_FOUND is returned.

    // Constraints: Given universe and object id exists.

    ===================================================

    rlCoordinate FindObject( rlUniverse* aUniverse, rlObjectId* aId )

    {

    if ( !aUniverse ) raise some exception.

    if ( !aId ) raise some other exception

    for ( int x = 0; x < UNIVERSE_X_SIZE; x++ )

    for ( int y = 0; y < UNIVERSE_Y_SIZE; y++ )

    for ( int z = 0; z < UNIVERSE_Z_SIZE; z++ )

    if ( aUniverse->FindObjectAt( aId, x, y, z )

    return rlCoordinate( x, y, z );

    return RL_NOT_FOUND; // maybe it's in other universe ;-)

    }

    @others:

    I think in principal if you find multiple exits, break, continue, single exit, exceptions, etc too complicated you're in the wrong industry. Also not seeing some exit points sounds like u need better glasses, power on you're monitor or something like that.

    Break, continue, goto, exceptions as well as multiple exits were all made for purpose and need. They all got their places and shouldn't be avoided by some stupid conventions. Somebody says developers not smart enough to use them properly is the source of problems. I'd say yes and no; simply: don't hire guys who can't do good code because they're causing problems and by hiring them you're actually the one causing problems.

  47. liar

    @Chris W

    (Not that I was the one who made the original challenge, and not that portability was the point, but let's see if I can answer this).

    Firstly I would say that if you are trying to port assembler from one instruction set to another then you should almost certainly be starting again from scratch. My comments on portability were aimed more at moving from one family member to another within an instruction set. A few years ago there was a trend for increasing pipe-line lengths and code that did this kind of thing tended to get caught out. Too clever for it's own good.

    However to answer your contention I am not aware of any main-stream processors which don't have the ability to load from an address specified in a register. Assuming you can do this then you just have to load the register with the base address then add the offset, then load.

    ie (in pseudo assembler)

    Mov r1,x

    Add r1,W

    Ldr r2 from r1

    Can you think of a sensible processor which is not able to do this?

    To be honest if you are coding in assembler then I think most programmers would agree that a different set of rules should apply from those used in a higher level language. In C you can always manage a look-up table with arrays, and let the compiler find the best way to do it.

    Nowadays even in embedded applications you should only rarely be venturing into assembler, and usually only then for horribly speed or space constricted bits of code.

  48. Geoffrey Summerhayes
    Stop

    Torches and pitchforks!

    This is ridiculous.

    I have a pipe cutter in my *real* toolbox. I don't use it often (twice, actually), but it's there when I need it. Same with multiple exits and gotos, most of the time they don't get used.

    But when not using them creates a plethora of meaningless boolean flags and nested if-clauses that start taking up more room than the code that does the actual work in the code, out they come...

    One of my uni profs sent out a problem to his classes he was having trouble with, a simple data parsing problem, took about half an hour to write and debug, wrote it with about 8 gotos. He wrote back that the idea of using gotos never occured to him, he was getting mired in working out the logic of a more structured approach. It was also the only fully working solution he had received.

    Multiple exits, like gotos are part of a programmer's toolbox. It doesn't mean they should be used all the time, but saying they should never be used is just as moronic.

  49. bobbles31
    Thumb Up

    Coding Standards

    As with all rules of thumb they are guidelines and the context in which you are coding must always be considered when coding.

    Most systems I write don't have to be performant in the Guided Missile Real time system sense so I like to mandate that the code be readable first and fast second.

    I also like to limit the length and purpose of procedures wherever possible. One of the code review requirements for a company I used to work for was that no procedure should be more that 60 lines. If it was you had to justify it to the nth degree or refactor it into more manageable chunks.

    So many times I have met developers though that are almost "Single exit point fundamentalists" or "Java/C#/[Insert technology of choice] fundamentalists." at the end of the day anything we write has to be 1) paid for and 2) maintained long after we are gone. So the only rules of thumb I have are ..

    1) where possible use the right technology for the job.

    2) Code like your going to have amnesia tomorrow and won't be able to remember why you chose to write something a certain way.

  50. Rich Silver badge

    Re "Challenge" by Juha-Matti Myllylä

    Firstly...

    "I think in principal if you find multiple exits, break, continue, single exit, exceptions, etc too complicated you're in the wrong industry. Also not seeing some exit points sounds like u need better glasses, power on you're monitor or something like that."

    I'm pleased I don't work on your team with an attitude like that! THAT is the attitude of a sloppy hack, and I can just imaging the quality (or rather lack of it) of the code that you write. I'll bet anything you like it's difficult and expensive to maintain, difficult and time consuming to understand, and buggy. Comments like that represent the reprehensible attitude of someone who lacks style and discipline.

    As for your "challenge"...

    You are having a laugh, no? If you can't code this with a single return then you are, frankly, hopeless.

    Firstly, there's no need to do anything about the exceptions. As I said in a previous post, if you are using exceptions to control program flow then you need to go back to school. So I can assume that having an exception here represents a fatal error, so it doesn't really matter any more that the program flow is broken because we have a fatal flaw in the code anyway that needs fixing.

    As for the two "returns" at the bottom of the code, ie...

    return rlCoordinate( x, y, z );

    return RL_NOT_FOUND; // maybe it's in other universe

    ...well, let me see now? Set a variable (remember those?) to a default value of RL_NOT_FOUND at the top of the function and then set it to an appropriate value from the value of the call to rlCoordinate(). Then return your variable at the end of the function.

    End result - clean program flow. Improved readability. Improved maintainability, etc etc...

    Or is that too difficult for you to understand?

Page:

This topic is closed for new posts.