C/C++[C++] Never have more than 1 return statement?
Thread starterJamin2112
Start date
AI Thread Summary
The discussion centers on the debate over whether a function in C++ should have only one return statement. Some argue that having multiple return points can enhance readability and simplify code, especially in cases involving preconditions or error handling. Others advocate for a single exit point to improve debugging and maintainability, citing traditional coding standards and practices. The conversation highlights the tension between modern coding practices and older rules, with some participants suggesting that the single return point rule is outdated. Ultimately, the effectiveness of return statements depends on the context and complexity of the function being written.
#1
Jamin2112
973
12
I know someone at Google who says you should never have more than 1 return statement in a function. That seems ridiculous to me.
Let's take a simple example. Suppose we need a function that finds the maximum value of any C++ array.
I can do
Code:
template <class T>
bool max (T* arrPtr, size_t n, T highest)
{
if (n == 0)
{
return false;
}
else
{
for (T* i(arrPtr), j(arrPtr + n); i != j; ++i)
if (*i > highest)
highest = *i;
return true;
}
}
or, equivalently,
Code:
template <class T>
bool max (T* arrPtr, size_t n, T highest)
{
bool retval;
if (n == 0)
{
retval = true;
}
else
{
for (T* i(arrPtr), j(arrPtr + n); i != j; ++i)
if (*i > highest)
highest = *i;
retval = false;
}
return retval;
}
Apparently, the first is considered bad because it has two return statements? The second seems very n00b-esque to me. (I know there's an even better way to do the whole function.)
This advice was popularized in "Code Complete" which suggested you minimize returning early except when it would enhance readability.
The "single point of entry / single point of exit" rule goes back much further than Code Complete. This rule is very old. The first part of the rule gives a clue as to how old this rule is. The facility to define alternate entry points to a function doesn't exist in C or C++, or in most other languages for that matter.
It's an old rule based on archaic concepts. It deserves to die.
I find the biggest benefit of the "one exit point" that you only need to set one breakpoint when debugging.
This benefit goes away with debuggers such as gdb that let you set a break point on the function's closing bracket.
Another supposed advantage of a single exit point is cleanup. Suppose a function creates and connects to a socket, opens a C-style stream, allocates an array via new, copies data from the socket to the stream, and then cleans things up. There are lots of things that can go wrong here. There's no point in continuing if the socket won't open properly, and then there's no stream to close, no array to delete. There are multiple ways in which the socket connection can fail, and the socket can fail while reading from it. The cleanup can be *ugly*. In fact, some advocate using goto to branch into the right part of the cleanup section.
There is a way around this cleanup problem in C++: Use RAII. Do this consistently and once again the impetus driving a single exit point vanishes.I'm a fan of "early exit". Suppose you've done a good job defining your functions in terms of preconditions, invariants, and postconditions. What to do about those preconditions? Suppose you are reading a complex function and the first thing you see are a handful of statements of the form
You know exactly what these checks are doing: They're ensuring the preconditions are met. That's the principle of least astonishment at work. The alternative of a single exit point can be more astonishing. You have to scroll all the way down to see that these preconditions just exit. Even worse, you may have to diagram some rather convoluted logic introduced just to comply with the "single point of entry / single point of exit" rule.
Though if you are keeping your functions small and uncomplicated this probably won't be much of an issue anyway.
Yep. The arguments I've seen for single point of entry / single point of exit are usually straw men. For example,
Code:
// 100s of lines of code elided
if (some_test) {
return ERROR_CODE_1;
}
// 100s of lines of code elided
for (i = 0; i < first_limit; i++) {
// 100s of lines of code elided
if (some_other_test) {
return ERROR_CODE_2;
}
// 100s of lines of code elided
for (j = 0; j < second_limit; j++) {
// 100s of lines of code elided
if (yet_another_test) {
return ERROR_CODE_3;
}
// 100s of lines of code elided
}
// 100s of lines of code elided
}
// 100s of lines of code elided
return SUCCESS;
That this code has four exit points interspersed randomly throughout several hundred lines of code is only the tip of the iceberg of the problems associated with this block of code.
#6
craigi
615
36
The rationale behind it, is that if someone who is unfamiliar with the code wants to do something at the end of the function for all cases, then they can miss a return point and introduce a bug.
People who analyse this sort of stuff can estimate how often mistakes like this happen and their cost to a project. Future languages may even make it impossible.
I do it some cases, but then I'm mindful of how someone might modify my code and what I want the compiler to do with it.
The rationale behind it, is that if someone who is unfamiliar with the code wants to do something at the end of the function for all cases, then they can miss a return point and introduce a bug.
How did they know they wanted to do something at the end for all cases, unless they traced all the possible ways they could get to the one return point?
Thinking or assuming they wanted to do something in all cases (e.g. by believing or misunderstanding the documentation, but not actually reading the code) might also be a bug!
The rationale behind it, is that if someone who is unfamiliar with the code wants to do something at the end of the function for all cases, then they can miss a return point and introduce a bug.
I've heard lots of excuses for the "single point of entry / single point of return", but I haven't heard this one before. That's pretty lame.
People who analyse this sort of stuff can estimate how often mistakes like this happen and their cost to a project.
Name one. Citation needed.
Future languages may even make it impossible.
This thread isn't about speculative directions in computer language development. It's about C++.
That said, those future languages will most likely formalize the concepts of preconditions and postconditions. That isn't the case in C++, which is why you will oftentimes find code that implements those preconditions in the form of early exit or throwing an exception.
In addition to those early exits, another common use for multiple returns in C++ is a search function. These two paradigms, using return statements for preconditions and a successful search, are widely used and widely accepted amongst professional C++ programmer.
Can return statements be abused, make code more confusing? Of course. Just because they can do so when used inappropriately does not mean they almost always do. More importantly, there are places where a return statement can enhance readability / understandability.
#9
craigi
615
36
AlephZero said:
How did they know they wanted to do something at the end for all cases, unless they traced all the possible ways they could get to the one return point?
Thinking or assuming they wanted to do something in all cases (e.g. by believing or misunderstanding the documentation, but not actually reading the code) might also be a bug!
When you're working with other people's code, you don't always fully understand the functions that you're modifying nor do you always need to. It's not ideal, but many experienced software developers have experienced, it at some point.
D H said:
I've heard lots of excuses for the "single point of entry / single point of return", but I haven't heard this one before. That's pretty lame.
It's certainly not lame if you're working on very large scale, safety critical projects.
D H said:
Name one. Citation needed.
Jean Ichbiah et al took this very seriously, for example.
D H said:
More importantly, there are places where a return statement can enhance readability / understandability.
Agreed. Very small functions and functions that are clearly structured for early-outs, are good examples. If you care about performance, they can also be used to coax the compiler into generating more optimal code, in certain cases.
Jamin2112 said:
I can do
Code:
template <class T>
bool max (T* arrPtr, size_t n, T highest)
{
if (n == 0)
{
return false;
}
else
{
for (T* i(arrPtr), j(arrPtr + n); i != j; ++i)
if (*i > highest)
highest = *i;
return true;
}
}
or, equivalently,
Code:
template <class T>
bool max (T* arrPtr, size_t n, T highest)
{
bool retval;
if (n == 0)
{
retval = true;
}
else
{
for (T* i(arrPtr), j(arrPtr + n); i != j; ++i)
if (*i > highest)
highest = *i;
retval = false;
}
return retval;
}
Regarding the OP, both of those functions are completely horrible. More structure to your programming will certainly help and in this case, a single exit should actually make your code simpler. Perhaps then you'll actually see the bugs in it. I can see 2 reasons why the first function doesn't even work straight away, one very dubious omission and one extra bug introduced by refactoring it for the second function.
McCabe's static code metric algorithm actually counts function returns as part of determining 'cyclomatic complexity' - a measure of the feasibility of code testing, primarily a result of code branching. It is old.
McCabe T. J., "A Complexity Measure". IEEE Transactions on Software Engineering 1976
My point is not about McCabe's approach, good or bad, but the fact that the algorithm counts "extra" return statements as negative dings the to the overall result. More returns are supposed to be bad. I believe this kind of thing has fostered the idea: 'more than one return in a function is bad'
@craigi - on PF, and in Science in general, a citation means just that: author,( journal or book) title, article title or chapter citation, date.
The most common reference for Jean Ichbiah is understandably: Ada
#12
craigi
615
36
jim mcnamara said:
@craigi - on PF, and in Science in general, a citation means just that: author,( journal or book) title, article title or chapter citation, date.
The most common reference for Jean Ichbiah is understandably: Ada
Sure, but I'm already happy with my contribution to the thread. Thank you for your contribution too. Searching for citations to support what we both already know seems fruitless and I'm content for anyone who doubts it to disregard it, out of hand.
It's certainly not lame if you're working on very large scale, safety critical projects.
That is what exactly what I do: Projects in the MSLOCs that can result in billions of dollars of damages, loss of life, and loss of national prestige.
But don't take my word for it. Let's look at a coding standard for a large scale, safety critical project that has been widely promulgated throughout the large scale, safety critical C++ community, the Joint Strike Fighter C++ Coding Standard (http://www.stroustrup.com/JSF-AV-rules.pdf) (emphasis theirs):
4.13.2 Return Types and Values AV Rule 113 (MISRA Rule 82, Revised)
Functions will have a single exit point.
Rationale: Numerous exit points tend to produce functions that are both difficult to understand and analyze. Exception: A single exit is not required if such a structure would obscure or otherwise significantly complicate (such as the introduction of additional variables) a function’s control logic. Note that the usual resource clean-up must be managed at all exit points.
Note that this is a will rather than a shall requirement, and also note that the rule has an explicit exception.
Jean Ichbiah et al took this very seriously, for example.
That is not a citation.
jim mcnamara said:
McCabe's static code metric algorithm actually counts function returns as part of determining 'cyclomatic complexity' - a measure of the feasibility of code testing, primarily a result of code branching. It is old.
McCabe T. J., "A Complexity Measure". IEEE Transactions on Software Engineering 1976
My point is not about McCabe's approach, good or bad, but the fact that the algorithm counts "extra" return statements as negative dings the to the overall result. More returns are supposed to be bad. I believe this kind of thing has fostered the idea: 'more than one return in a function is bad'
Whether return statements raise the cylcomatic complexity is subject to debate. A return statement is equivalent to goto __close_brace. It's just another edge in the local graph. On the other hand throwing an exception, calling exit, or calling some project-specific function that acts like an exception (i.e., the function doesn't return to the caller) is an alternate exit point, and they do bump the complexity.
For references, the Apple/IBM Taligent project published a Taligent's Guide to Designing Programs, Well Mannered Object Oriented Design in C++
While Taligent is defunct, the guide is still useful for coding standards.
On page 52 Things to Avoid: Don't Use goto
They mention avoiding the use of returning from the middle of a procedure as something that should be reviewed with the project architect. The reasoning is that it could subvert the meaning and correctness of the code requiring you to read all the relevant code to see what's going on.
The problem with over-simple "rules" is that they are too easy to subvert, as in the OP's code where "goto end-of-function" is replaced by the state variable "retval" which has no other purpose in the code. One of my work colleagues used to call this style of coding "the if-come-from statement" or "backwards programming" (and less complementary names which probably don't meet the PF posting guidelines!)
Of course there are much more creative ways to subvert a "no gotos" or "only one return" rule than he OP's method, as D.H. already mentioned - throwing user-defined exceptions, etc.
I've only seen the use of goto "justified" in a tiny number of cases.
Case 1 (very rare): The code gets in trouble deep inside multiply nested loops. This can happen, for example, with some bizarre corner cases in singular value decomposition. While SVD is typically very robust, there are some weird corner cases that defeat this robustness. The problem is that the problem isn't uncovered until deep in the bowels of the SVD algorithm. There would be no problem with this problem if C/C++ had a multilevel break capability. The goto statement provides a way to emulate this missing capability.
Case 2 (much more common): Some fool of a manager has mandated the single point of entry / single point of exit rule, with no exceptions allowed. Some programmer complains that the only alternatives are to add unneeded complexity to the code or to use gotos. The manager's response: "That's right. This is one of those cases where gotos are the preferred implementation."
I for one much prefer to see preconditions dealt with up-front in a manner that clearly calls them out as such. A small (one to three) statement blocks of the form if (simple_test) { log_error(); return; } at the head of a function won't bug me in the least -- so long as those preconditions are clearly documented. Those up-front statements tell a nice Principle of Least Astonishment story.
On the other hand, I've been asked to participate in a code review of a function with over 200 lines of code and a cyclomatic complexity in excess of 20. Those numbers alone bedeviled me beyond belief. That that tangled mess of code of contained buried return or goto statements will just cemented the deal.
I may be the only one here who really remembers where the "one exit" rule came from.
It was in rebellion to "spaghetti code" - especially prevalent among FORTRAN programmers doing maintenance coding. It came with strict adherence to the basic programming structures ("structure programming").
There is clearly some absurdity to it - as there was with the strict dictates of structure programming. Although it was (and is) true that you could not have spaghetti code with strictly structured programming, what you do get is truly obscure flags to signal which path you want to take.
Personally, I do subscribe to "GOTOless" code - although I wouldn't go so far as to forbid it. My main concern is being able to follow the code - and until you've tackled a system with hundreds of pages, you;re probably not going to catch on to what that means.
Basically, you should realize that there are many ways to implement an algorithm and the one you want to pick is the one that has an easy to follow human-language "story".
As far as single exit coding, like craigi, I commonly deal with safety related or military mission-critical systems and so I give the auditors their due. Some people feel very strongly that there should be only one exit - and I do not care to spend my time fighting them.
So, here is how I would implement the code - allowing for one exit while retaining "sensibility":
Code:
template <class T>
bool max (T* arrPtr, size_t n, T highest)
{
bool bOkay;
//
// Check valid input (or any other description of why your are checking "n")
bOkay = n != 0;
if(bOkay)
{
for (T* i(arrPtr), j(arrPtr + n); i != j; ++i)
if (*i > highest)
highest = *i;
}
return bOkay;
}
Sometime the solution is not quite so simple. Very commonly, there will be many, many exit conditions. The most common solution for avoiding numerous "returns" is to start nesting if statements - one or two levels of nesting for each error condition checked. For example, you're opening a file and you want to check the file name, whether it can be opened, whether a malloc works, whether the filesize is adequate, whether the first 10 bytes are "MyFileType", etc. Wouldn't you love to go "if(!malloc(...)) return MYERR_MALLOC;"?
Here's one not-that-bad method - using an enumeration variable "eErrorState":
So, here is how I would implement the code - allowing for one exit while retaining "sensibility":
Code:
template <class T>
bool max (T* arrPtr, size_t n, T highest)
{
bool bOkay;
//
// Check valid input (or any other description of why your are checking "n")
bOkay = n != 0;
if(bOkay)
{
for (T* i(arrPtr), j(arrPtr + n); i != j; ++i)
if (*i > highest)
highest = *i;
}
return bOkay;
}
This is a beautiful illustration of 2 things that I was talking about earlier in the thread.
Firstly, it's the simplification that I was referring to that the single exit point paradigm offers in this case.
Secondly, it's easy to see from it how programmers make modifications to functions that they don't fully understand. This shouldn't be taken as a critisism of .Scott, rather just as an observation of how a programmer typically modifies unfamilar functions. In this case he has rightly presumed that he could do no harm to this function by modifying it to have a single exit point, but has also inadvertently copied the 3 serious issues, from the OP's original function, that I was referring to earlier.
Now this is an incredibly simple function. In the case of a more complex function, it really isn't a huge leap of the imagination to see how a programmer attempting make a modification to a function without understanding it in its entirety actually introduces new errors in the false belief that they have done no harm. A more structured programming style defends against these scenarios.
I actually take a very liberal approach to coding standards, but they can serve as a very useful learning resource for inexperienced programmers. Enforcing coding standards is no fun for anyone, but if I were confronted with someone checking in any of the iterations of this function in this thread to a codebase that I was using, I would just delete and rewrite it.
craigi, while you may see .Scott's solutions as "beautiful", those who advocate early return as the preferred mechanism for dealing with invalid inputs (failed preconditions) will inevitably use a rather different adjective to describe that code. I see what .Scott's wrote as exemplifying why one *should* use early return rather than shun it.This is a programming religion issue. As far as I can tell, there are no studies that compares "single point of entry / single point of return" versus early return with regard to readability, understandability, maintainability, etc. There's only religion. From my experience, mandating religious issues rarely works. Those religious mandates cause managers to tell the programmers who work for them to ignore the programming standards. All of them. I've seen this happen, multiple times.
The "single point of entry / single point of return" rule ranks right up there with regard to causing dissension as do the "no magic numbers" rule (which taken to its extreme results in nonsense such as #define ZERO 0) and the yoda convention rule (which results in inscrutable code such as if (ZERO != number) ...).
Last edited:
#20
Jamin2112
973
12
craigi said:
Regarding the OP, both of those functions are completely horrible. More structure to your programming will certainly help and in this case, a single exit should actually make your code simpler. Perhaps then you'll actually see the bugs in it. I can see 2 reasons why the first function doesn't even work straight away, one very dubious omission and one extra bug introduced by refactoring it for the second function.
I feel like an idiot sometimes. I understand that I didn't pass highest as a reference and didn't initialize it inside the function.
How about this:
Code:
template <typename T> T max(T* arr, size_t n)
{
if (n == 0) /* I know most people programmers prefer "if (!n)" */
throw("The max of an empty array is undefined, bro.");
/* The rest doesn't need to be in an "else" statement, even though the intent of
the function is to execute the rest of the code only if the "if" condition isn't met */
T highest = arr[0];
for (T* i(arr+1), j(arr+n); i != j; ++i)
/* Pointer arithmetic starting at the memory address after the first element of the array and
continuing until one-off-the-end of the array */
if (*it > highest)
highest = *it;
return highest;
}
I'm sure a C++ purist will have some fancier routine that involves forward iterators, recursion, etc.
craigi, while you may see .Scott's solutions as "beautiful", those who advocate early return as the preferred mechanism for dealing with invalid inputs (failed preconditions) will inevitably use a rather different adjective to describe that code. I see what .Scott's wrote as exemplifying why one *should* use early return rather than shun it.
This is a programming religion issue. As far as I can tell, there are no studies that compares "single point of entry / single point of return" versus early return with regard to readability, understandability, maintainability, etc. There's only religion. From my experience, mandating religious issues rarely works. Those religious mandates cause managers to tell the programmers who work for them to ignore the programming standards. All of them. I've seen this happen, multiple times.
The "single point of entry / single point of return" rule ranks right up there with regard to causing dissension as do the "no magic numbers" rule (which taken to its extreme results in nonsense such as #define ZERO 0) and the yoda convention rule (which results in inscrutable code such as if (ZERO != number) ...).
I agree. My motivation for creating such code is to placate high priests.
The real problem is that there is such a thing as "bad code" - as demonstrated by the widespread success of computer viruses that exploit bad code. This real problem motivates some managers to establish "coding standards" to prohibit "bad code". Unfortunately, you can't turn bad cooks into good cooks by forcing them to hold their cooking utensils in special aesthetically graceful ways. It may make the cooking look better - but you'll still get indigestion.
#22
craigi
615
36
Jamin2112 said:
I feel like an idiot sometimes. I understand that I didn't pass highest as a reference and didn't initialize it inside the function.
How about this:
Code:
template <typename T> T max(T* arr, size_t n)
{
if (n == 0) /* I know most people programmers prefer "if (!n)" */
throw("The max of an empty array is undefined, bro.");
/* The rest doesn't need to be in an "else" statement, even though the intent of
the function is to execute the rest of the code only if the "if" condition isn't met */
T highest = arr[0];
for (T* i(arr+1), j(arr+n); i != j; ++i)
/* Pointer arithmetic starting at the memory address after the first element of the array and
continuing until one-off-the-end of the array */
if (*it > highest)
highest = *it;
return highest;
}
I'm sure a C++ purist will have some fancier routine that involves forward iterators, recursion, etc.
1 old bug which I'd still argue wouldn't have existed if your code had a more structured style.
1 new bug, but to be fair it looks like a typo.
They're both compile errors so running it through a complier will throw them up.
Don't worry about forward iterators or recursion, but if you want to improve on it, pay particular attention to the use of copy constructors. If T is a built-in type then it makes no difference, but for class types things get more complicated. You've actually hit on a little quirk of C++ called "named return value optimisation", which means that your function can actually have different behaviour on different compilers! You can write this entire function without involving a single copy constructor, which might serve as a useful exercise.
Also, think about your motivation for using c++ exceptions. If the only reason is to dodge the single exit point debate, then it's a heavy price to pay. The bottom line is that you should be mindful of where you put your exit points. You can argue it either way and for such a small function it makes very little difference.
You're also using the assignment operator for T a lot more than necessary:
Code:
T highest = arr[0];
for (T* i(arr+1), j(arr+n); i != j; ++i)
/* Pointer arithmetic starting at the memory address after the first element of the array and
continuing until one-off-the-end of the array */
if (*it > highest)
highest = *it;
return highest;
Why not just keep track of the index of the maximum, and then at the end, return the array element at that index? Something like
Code:
size_t idxOfMax = 0;
for (size_t i = 1; i < n; i++)
if (arr[i] > arr[idxOfMax])
idxOfMax = i;
return arr[idxOfMax];
#24
harborsparrow
Gold Member
716
231
Every rule has an exception. The example given is trivial and thus, it does not harm to return from 2 different places. However, for long subroutines or functions, returning from multiple places can lead to difficult-to-read code. The real point made by Code Complete, the book famous for promulgating this rule, is to make your code easily understandable to any outsider who looks at it, or might have to maintain it in the future. As long as you keep this principle firmly in mind, you'll be OK.
One advantage to returning from a single point can be if you are logging progress--the code which logs progress need only be in one place. After many years of coding experience, I began logging progress in all my code. This enabled me to troubleshoot when I got unexpected reports of errors from users--I could see what they had been doing when the error occurred. So I logged, not just errors, but basic calls (and results returned). This had to be done efficiently but was a capability well worth developing. I always log as I enter and leave a function. The slight overhead of this has been well worth it, and if the overhead cannot be afforded, then you can make the logging itself have an on/off capability. But I found it held me to the discipline of having a single point of return.
Some people will fight this, but I am very, very experienced at writing user interface code that goes to a lot of users. They always, always, encounter something what wasn't caught in testing, and mechanism such as single point of return, with error logging, can save your bacon when that happens. My current group of a dozen or so users have grown so accustomed to this that they now automatically send me their log files along with any trouble report. Saves a mountain of time for everyone. 99% of the time, the log file directs me quickly to the problem.
I always log as I enter and leave a function. The slight overhead of this has been well worth it, and if the overhead cannot be afforded, then you can make the logging itself have an on/off capability. But I found it held me to the discipline of having a single point of return.
Why not instantiate an object whose constructor and destructor log the entry/exit? Then it's irrelevant whether you have a single point of return or not. I've done something similar when measuring the amount of time spent in various functions.
This rule is much older than Code Complete (a book that should be on every profession programmer's essential reading list). Steve McConnell was reiterating what *some* held as common wisdom. Here's what McConnell wrote in Code Complete:
Minimize the number of returns in each routine. It's harder to understand a routine if, reading it at the bottom, you're unaware of the possibility that it returned somewhere above.
Use a return when it enhances readability. In certain routines, once you know the answer, you want to return it to the calling routine immediately. If the routine is defined in such a way that it doesn't require any cleanup, not returning immediately means that you have to write more code.
Even McConnell left an out. (The authors of the JSF coding standards similarly left an out.) If return statements enhance readability and understandability, use them. If all they do is obfuscate, don't use them. A return statement buried deep in some convoluted logic has zero redeeming value.
Personally, I **hate** this rule on the basis that it causes more harm than good. The underlying intent is certainly good, but good intentions are what the road to the underworld is paved with.
#27
harborsparrow
Gold Member
716
231
jbunniii said:
Why not instantiate an object whose constructor and destructor log the entry/exit? Then it's irrelevant whether you have a single point of return or not. I've done something similar when measuring the amount of time spent in various functions.
This is a way to log. It might be less obvious to someone reading the code. And finding the deconstructor is not always easy.
There are also code injection technologies, if tracing code execution is all one is after.
I'm after a lot more than simply tracing execution. I may also log returned values upon exit. I'm always thinking about what I'd need to see in the log if a trouble report comes.
Personally, I like to stick to the "single point of return" rule most of the time, because I've found it helps me read the code again late--especially if I have to come back to it after a lot of time has lapsed.
Personally, I like to stick to the "single point of return" rule most of the time, because I've found it helps me read the code again late--especially if I have to come back to it after a lot of time has lapsed.
(bolding mine)
I think most of us agree with the general sentiment. As DH wrote, problems start when the rule becomes a religion.
IMHO that's the problem with most of the similar rules used in programming. They work great most of the time, but there are moments when religiously sticking to them just produces code that becomes unreadable, or unnecessarily complicated.
#29
gmar
25
0
Jamin2112 said:
I know someone at Google who says you should never have more than 1 return statement in a function. That seems ridiculous to me.
That's not in dispute. What this thread was about was whether it was good practice to have exactly one return statement in a function. As D H has said, this "rule" has become something of a religious controversy, akin to the controversy about where the opening brace for a for loop, while, loop, if block, etc. should go: on the same line or on a new line.
#31
gmar
25
0
Mark44 said:
That's not in dispute. What this thread was about was whether it was good practice to have exactly one return statement in a function. As D H has said, this "rule" has become something of a religious controversy, akin to the controversy about where the opening brace for a for loop, while, loop, if block, etc. should go: on the same line or on a new line.
There is certainly some dispute over the former issue.
As for the latter, your editor or IDE can automatically reformat code when you open it.
I am much more interested in the GOTO issue that was mentioned earlier in the thread. It's actually standard practice in quite a lot of places.
I do not think it's religion. It can simply be a case of insufficient self-introspection. A programmer assumes that his own field of programming as practiced by his cohorts represents the sum total of all programming and doesn't realize other subgroups are working in very different environments with different idioms.
#32
TylerH
729
0
I agree with most of the posts in this thread. IMO, it's completely pointless to force a single return when many would simplify the code. But I have a professor that enforces the single return rule on all of his assignments. I've mentioned to him that I think the rule is absurd (it's a small department and I know him well) and he responded by telling me that it messes up a lot of invariants necessary for a lot of optimizations. He did research in compilers at a upper-middle level school during his PhD, so he has the background to know this with certainty. I've never pressed him for what exactly it is that the multiple returns messes up, as it would likely be an involved discussion I wouldn't completely understand anyway (thus doing so would show inconsideration for the value of his time). I know this doesn't really mean much because I can't substantiate anything, but it might be worth considering. Does anyone here have any idea what he could mean?
PS Even knowing this, I still use multiple returns, mainly because I have a policy against coding for optimizations. I code algorithms. If compilers can't generate efficient code for an efficient algorithm, IMHO, that's the compiler writers' problem and not worth my effort unless it's causing me performance problems in a hot segment of code.
#33
craigi
615
36
TylerH said:
I agree with most of the posts in this thread. IMO, it's completely pointless to force a single return when many would simplify the code. But I have a professor that enforces the single return rule on all of his assignments. I've mentioned to him that I think the rule is absurd (it's a small department and I know him well) and he responded by telling me that it messes up a lot of invariants necessary for a lot of optimizations. He did research in compilers at a upper-middle level school during his PhD, so he has the background to know this with certainty. I've never pressed him for what exactly it is that the multiple returns messes up, as it would likely be an involved discussion I wouldn't completely understand anyway (thus doing so would show inconsideration for the value of his time). I know this doesn't really mean much because I can't substantiate anything, but it might be worth considering. Does anyone here have any idea what he could mean?
I seriously doubt that he's correct, that compilers don't handle multiple exit points well, but I think I can outline his argument, though it's difficult to explain stuff that is wrong.
Inside the body of a function that isn't to be inlined, the compiler assigns registers to variables. There's a finite number of registers available. If a register already contains a value that is needed after the function call, its contents needs to be stored on the stack, typically at the start of a function and the value needs to be loaded back into the register from the stack before exitting from the function. The stack is typically stored in the fastest memory available, but memory access is often significantly slower than register access.
There's extra complexity, in that different processors give different penalties for failed branch predicition, and in some circumstances, it's better to execute extra instructions and disgard their result in order to remove branches and dodge a branching penalty.
The reason I think it's not relevant, is that it's trivial for a compiler to unite exit points, in the same way that a programmer would. In fact, early exits allow compilers to use less registers, in those instances. Typically, when writing performance critical code, I would tend towards multiple exit points, rather than away from them.
Complier behaviour does vary and early releases of compliers have unexpected behaviours. Typically, compiler optimisation involves analysing the most common use-cases and mutiple exit points is a relatively common pattern. Nevertheless, if you're writing performance critical code, you tend to disassamble it anyway and modify the C++ to coax the compiler into producing the correct code. If it's stubborn, then moving to assembly is the only solution.
TylerH said:
PS Even knowing this, I still use multiple returns, mainly because I have a policy against coding for optimizations. I code algorithms. If compilers can't generate efficient code for an efficient algorithm, IMHO, that's the compiler writers' problem and not worth my effort unless it's causing me performance problems in a hot segment of code.
Whether or not you should optimise for performance, really depends upon the circumtances and there are cases where it's very important that a section of code completes within a fixed time on fixed hardware. Hoping that a new version of a complier is going to turn up before you need to meet that demand isn't a sensible solution. Alternatively, if it doesn't really matter to you how long it takes your code to complete, then you should prioritise other things such as maintainability and minimisation of bugs.
A good programmer, develops a style that practises all these considerations in a particular balance and constantly re-examines their style based upon how they currently percieve the desirable characterisitics of their code.
There is certainly some dispute over the former issue.
As for the latter, your editor or IDE can automatically reformat code when you open it.
That's problematic when you have to check your code into a revision control system and the project dicta that mandate that all checked-in code must be formatted per a strict set of rules. I've yet to meet an automated reformatting tool that properly converts all the nuances of style A to all the nuances style B.
To me, the easiest way around this problem is to relax those project-wide dicta. This becomes especially important for big projects, those with many tens of thousands lines of code or more. Should there be consistency within a file, or some logical grouping of files? Absolutely. Should there be consistency across a project that comprises a million lines of code? No. Now the project manager is imposing his or her own computing religion.
I am much more interested in the GOTO issue that was mentioned earlier in the thread. It's actually standard practice in quite a lot of places.
The only places where I've seen GOTO used are
In ancient code that dates from the 1970s or earlier.
In not so ancient code where the programmers saw 1970s era code as a "how to" example of best practices.
In some finite state automata, where the natural transition from one state to another is to go to that other state.
In organizations that have mandated the single point of entry / single point of return as an anti-pattern.
I have successfully shot down incorporating the single point of entry / single point of return rule into a project's coding standards by innocently asking "so does that mean we can use goto?"
To me, the easiest way around this problem (goto and return) is that code needs to be subject to peer review. It's impossible to specify in rules all of the ways that code can be "wrong". Someone used a O(n3) algorithm where an O(n log(n)) algorithm will do? That code is wrong, but try writing a programming standard that says not to do that. Humans remain the best bug detectors. That's why we review code. Stinky code ("code smell") is another area where standards just don't quite work. We all know stinky code when we get too close to the screen and smell it. Multiple return statements can be a sign of code smell. "Your code stinks" from a peer reviewer is always a relevant comment that needs to be addressed.
TylerH said:
I agree with most of the posts in this thread. IMO, it's completely pointless to force a single return when many would simplify the code. But I have a professor that enforces the single return rule on all of his assignments. I've mentioned to him that I think the rule is absurd (it's a small department and I know him well) and he responded by telling me that it messes up a lot of invariants necessary for a lot of optimizations. He did research in compilers at a upper-middle level school during his PhD, so he has the background to know this with certainty.
That is true to some extent. A return deep inside a multiply-nested loop is almost inevitably going to raise havoc with an optimizer. The same is true for goto and break statements. Those statements mess with the loop invariants, thereby precluding a lot of optimizations. On the other hand, an early return such as a check that the user input mass of an object is positive doesn't mess with those loop invariants. Advanced languages have a concept of preconditions and postconditions. Older languages such as C and C++ do not, and as a result you get design patterns such as early return.
A well-established design pattern in an older language is a built-in feature or perhaps even a no-op or in a more advanced language.
#35
gmar
25
0
D H said:
That's problematic when you have to check your code into a revision control system and the project dicta that mandate that all checked-in code must be formatted per a strict set of rules. I've yet to meet an automated reformatting tool that properly converts all the nuances of style A to all the nuances style B.
That's weird since doing a custom extension for an existing extensible code formatter is probably a weekend's work for an intern.
My programming background is embedded systems in C. We do a lot of things the majority of non-realtime coders don't like, but in all honesty, the majority of idiomatic code arguments are all based on soft factors so comparing it to a religion is a pretty good analogy. At least until, for example, we get some really good formal verification tool which chokes on multiple exit points in a function.
Now would probably not be a good time for me to mention the exception vs return code "debate".
I didn't like the tone of my reply, so I edited it.
In ancient code that dates from the 1970s or earlier.
In not so ancient code where the programmers saw 1970s era code as a "how to" example of best practices.
In some finite state automata, where the natural transition from one state to another is to go to that other state.
In organizations that have mandated the single point of entry / single point of return as an anti-pattern.
I have successfully shot down incorporating the single point of entry / single point of return rule into a project's coding standards by innocently asking "so does that mean we can use goto?"
I recall seeing goto being used in MS Windows internal OS code, possibly in kernel code, but it's been about 10 or 12 years, so I'm not sure of that. One rationale for its use, I believe, was that if something untoward happened, not as much unwinding of the call stack was needed.
I've read the phrase "arrow anti-pattern" more often, usually referring to if else sequences overly nested, spanning over 50 lines of code, resulting in the primary code path of a function being nested 4 levels or more deep, and the else handling code for the first if is at the very end of the nested mess, ... . This is where alternatives like goto or a state type variable are better.
I've read the phrase "arrow anti-pattern" more often, usually referring to if else sequences overly nested, spanning over 50 lines of code, resulting in the primary code path of a function being nested 4 levels or more deep, and the else handling code for the first if is at the very end of the nested mess, ... . This is where alternatives like goto or a state type variable are better.
One community's pattern is another community's anti-pattern.
This is quite common in C.
Code:
function allocate_and_process ():
a = allocate ()
if test (a) == fail:
goto UNDO_A
b = allocate ()
if test (b) == fail:
goto UNDO_B
c = allocate ()
if test (c) == fail:
goto UNDO_C
test_code = do_stuff (a, b, c)
return test_code // returns test result code
UNDO_C:
free (c)
UNDO_B:
free (b)
UNDO A:
free (a)
return COULD_NOT_RUN_TEST // returns value showing test could not run
Although it's common in C, if you do it in C++ you (usually!) get slapped. Not only do you have RAII, but it's not exception safe.
That's weird since doing a custom extension for an existing extensible code formatter is probably a weekend's work for an intern.
It might be a weekend's work for an intern to solve half of the problem. It's the other half of the problem, the nuances, that make this difficult. It's a bit like applying a translator that translates from English to Russian and then another that translates from Russian to English. The results, while amusing, are likely to be incorrect.
This is a big sidebar to this thread on never having more than one return statement, so if you want to continue this discussion it's best to start a new thread.
gmar said:
Now would probably not be a good time for me to mention the exception vs return code "debate".
Probably not. The single versus multiple return statement "debate" is enough programming religion for one thread.
On the other hand, the single point of return rule implicitly precludes throwing an exception. In fact, C++ projects that enforce single point of return also typically ban the use of exceptions. That in turn precludes using things such as C++ containers, and a number of realtime C++ projects do ban their use. Realtime programming is a different world.
gmar said:
One community's pattern is another community's anti-pattern.
Another way to look at it: That a design pattern exists in some language is a sign of a weakness in that language. The call stack is a design pattern in assembly; it's (mostly) invisible in high order languages. The goto exit_point widely used in C to address resource issues is (mostly) obviated in C++ programmers with RAII. Mmany C++ design patterns similarly become invisible or unnecessary in a dynamic functional programming language where classes and functions are first class objects.
This is quite common in C. <typical C function with multiple allocations and multiple gotos elided>
It is indeed very common, particularly in low level C code such as OS kernel code. It's a standard C design pattern to ensure that resources are properly handled. In fact, CERT recommends this style over multiple returns: https://www.securecoding.cert.org/confluence/display/seccode/MEM12-C.+Consider+using+a+goto+chain+when+leaving+a+function+on+error+when+using+and+releasing+resources .
Although it's common in C, if you do it in C++ you (usually!) get slapped. Not only do you have RAII, but it's not exception safe.
There's a lot of C++ code out there that isn't exception safe. Writing exception safe software is doable but is not easy. There's a lot more to it than try and catch. (In fact, one can write exception safe functions that don't use try and catch at all.)
Interestingly, C++11 has deprecated the very idea of listing the exceptions a function can throw. The new concept is the noexcept qualification, which is part of a function's signature. A function qualified as noexcept(false) (or no spec at all) can throw anything. A function qualified as noexcept or noexcept(true) guarantees that it will not throw, even indirectly.
Last edited by a moderator:
#41
harborsparrow
Gold Member
716
231
I figure it's about a 99% chance that I'll get flamed for what I'm about to say, but here goes anyway.
I've been writing code--and maintaining old code--for more than 3 decades. My field is computer science, not physics, though I've had to do my share of numerical code. The advice to have a single exit point (for any subroutine larger than a few lines) is sound, based on my experience. More than once, I've needed to install monitors in old code to troubleshoot it. This meant, in some cases, logging exit conditions. That was a lot easier to do when where was a single exit point.
You may think you'll never want to do anything like that, but I submit that you cannot know--if code lives for several years--what is likely to be needed in the future. Hence, the common advice is to use a single exit point in most cases. Note, I acknowledge that there are trivial cases where it would not matter.
You can blow me off as being an old fogie if you like, or cavalierly dismiss this as being "a religious war" in which there is no right answer. You can also kill yourself by drinking too much or smoking too much despite obvious and widespread evidence that those things will kill you.
Yes, a "go to" like structure is required to implement this in some cases. The payoff of doing it is, there is a single exit point WHERE YOU CAN WRITE CODE THAT EXECUTES IN ALL CASES on the way out. In any subroutine that is larger than will fit on the screen at one time (and hence, harder for a code reader to understand), the single-exit-point tactic will be helpful to anyone maintaining that code far in the future.
The most despicable old code not only has multiple exit points, but those exit points are not easily identifiable. That is, there is no "return" statement at the actual point of exit. It just happens that that's where the thread of execution sometimes ends up, thus falling through to the bottom and exiting anyway. I have learned to value readability of code much higher after years of taking care of code that I wrote when I was in a hurry. So even if you include a "break" statement that kicks you out of a multiple-choice selection, adding a comment saying "done, let's exit" or something can be helpful.
It amazes me that people put up such strong resistance to something that has proved so useful over time.
I figure it's about a 99% chance that I'll get flamed for what I'm about to say, but here goes anyway.
I'll try not to flame.
This is a question about C++. Different languages have different design patterns. The single point of entry / single point of return is a very old rule aimed at very old languages where responsibility for cleaning up resources is almost entirely the responsibility of the caller rather than the callee. The single point of entry part of the rule has pretty much been removed. Multiple entry points was one of the many failed experiments in computer languages.
What you described is a rather old school way to test code. A more modern view is that you test some function by writing a driver that calls the function in various ways. An even more modern view is that you write the test *before* you write the function. The test is the spec.
That's the ideal. The ideal and reality don't mix well. You never quite know what some programming construct is supposed to do until you write the construct, and then find you didn't think of all the angles. So you refine the test as you refine the code. The basic idea still holds, though: The test is the spec.
All of that ugly scaffolding and stubbing needed to test the artifact should in the unit test code. The subject of the test is nice and clean. There's little need to add garbage to the "real" code. Where you do, well, In C++ you can do some nasty stuff amongst friends. If the unit test code is a friend of the class under test, that test driver can poke into private parts. This is subject to some debate. Do you need to test the private interfaces?
#43
gmar
25
0
I am not sure this is a C++ question. The OP did not mention what language the Google engineer he quoted was working with and the OP himself chose to consider the statement only within C++. If the original source was referring to C++, you have to also consider Google's C++ style guidelines disallow the use of exceptions, and as I have stated many times, exceptions are effectively additional function exit points.
I am not sure this is a C++ question. The OP did not mention what language the Google engineer he quoted was working with and the OP himself chose to consider the statement only within C++.
While the OP did not specify the language posed by the Google engineer, he did pose the question in terms of C++. Different languages have different design patterns. The single entry / single return design pattern is aimed at older languages that don't have a concept of objects that clean up their mess (e.g., RAII in C++). In more modern languages you're much more likely to see a return (or throw) early design pattern.
If the original source was referring to C++, you have to also consider Google's C++ style guidelines disallow the use of exceptions.
The Google C++ style guidelines is widely perceived as a "how not to do it" example. It is rather old style, it actively encourages some bad habits. Strictly speaking, the "no exceptions" rule pretty much rules out the C++ standard library. One legitimate place you will see the "no exceptions" rule is in embedded programming. For example, the Joint Strike Fighter rules has this rule (but only because of adequate tool support; that standard is written about ten years old).
A much better guideline for non-embedded programming is C++ Coding Standards: 101 Rules, Guidelines, and Best Practices by Herb Sutter and Andrei Alexandrescu. This book is also ten years old, but it has a much more modern point of view. Exceptions are encouraged rather than discouraged (but only for truly exceptional problems). Since every file has an EOF, hitting EOF should not be treated as an exception. Users always mess up when typing in data; goofy user input is not an exception.
Sutter and Alexandrescu's Rule #0 is "Don't sweat the small stuff." That includes things like specific indentation rules. Code should be indented, but exactly how is inevitably going to cause friction. They also take my stance on modifying other peoples code. The modifier should adapt to the existing style.
Sutter and Alexandrescu explicitly call out Hungarian notation and single entry / single return as two old-style rules that should be avoided.
I have stated many times, exceptions are effectively additional function exit points.
That is exactly how they function from a McCabe complexity point of view. Multiple return statements do not function that way. Draw the graph of the function. Those multiple return statements all return to the statement after the call to the function. Exceptions "return" somewhere else up the call stack, even to the function that calls main() if the exception isn't handled. The same goes for calls to exit(), abort(), many calls to kill(), and calls to locally written functions that do not return (because they in turn throw or call exit, abort, or kill). Those are the alternate exits that McCabe warned about needing to be counted rather than multiple return statements.
Finding a tool that counts complexity correctly is not easy. Consider this code:
Many compilers will generate the exact same machine code for all three functions. There is no difference between them. All three functions have the same cyclomatic complexity, two. Many tools don't even get the if-else version right; they report the complexity as one. Straight line code has a complexity of zero with these tools. Some tools get the if-else version wrong and report a complexity of three because of the presence of the else clause. Many tools miss the ternary operator, seeing that as straight line code. It's not. Most tools count the switch implementation as more complex than the if-else implementation, even the ones that don't mistakenly bump the complexity for the else statement.
I've yet to see a tool that properly bumps the complexity for alternate exits but not for multiple returns. How to do this for calls locally-written functions that do not return? The only way I can see how to properly count these is to mandate commenting the line after such calls with "// NOT REACHED" and counting those comment lines.
#45
gmar
25
0
There's a lot of points to cover in this thread.
We know their (Google's) C++ style is possibly controversial but the point is, firstly if a Googler said "only use single points of return" then, assuming he meant C++, it has to borne in mind the environment in which he works, and secondly, when considering that environment i.e. those guidelines, one has to consider that they are intended to work with the company's current codebase.
In my opinion, to go into more detail about JSF the 'toolset driven' reason D H quotes that they cite for disallowing exceptions is almost certainly related to the unpredictability of the execution time. I don't think that's been directly solved but the situation is improving. In an ideal world, both systems programming and embedded would have the same intolerance of code failure.
In terms of exceptions being more common in newer code, mostly, but I see a movement away from them as concurrency takes off. My current toy is Rust, which does not have true exceptions. I could talk for ages on Rust but I won't. :-)
I don't do or understand cyclic complexity. To me it is another of those measurements that non-technical managers like to add in, like SLOC. Code review goes quite a long way towards addressing this issue. Perhaps when the formal verification guys can actually deliver, it may become more important for me if the tools only work on code with a complexity under a certain threshold.
I don't really get why people have trouble with source code formatters. In my mind the technical issue stems from whitespace, most commonly where you break a long line. This isn't problematic if handled consistently, which may involve reformatting non-compliant legacy code. (What is the point of having a standard if you accept code that violates it?) In my experience the other problems are human-related i.e. procedural. (Time to get new job, as D H would say!)
#46
voko
6,053
391
The simple fact is that a lot of C++ programmers deal or have dealt with a lot of C code. A lot more deal with the C++ code that has been created or maintained by programmers dealing or having dealt with a lot of C code.
In C, "the single point of return" is almost invariably the only way to deal with the cleanup and debugging requirements rationally. That rationale, using the chain I described above, gets transferred to C++ coding, where it is certainly double and does not look completely wrong. However, as already stated, it is not necessarily the best way in C++ to address the underlying problem: cleanup and debugging. It may be OK, but it is certainly not by default.
#47
harborsparrow
Gold Member
716
231
D H said:
I'll try not to flame.
What you described is a rather old school way to test code. A more modern view is that you test some function by writing a driver that calls the function in various ways. An even more modern view is that you write the test *before* you write the function. The test is the spec.
Granted the above to be true. However, a great deal of programming work is managing code that was written before the above ideal became common. And in languages lacking a test case harness. Much of the code I currently manage (for a team of biologists) fits this mold.
In my opinion, to go into more detail about JSF the 'toolset driven' reason D H quotes that they cite for disallowing exceptions is almost certainly related to the unpredictability of the execution time. I don't think that's been directly solved but the situation is improving. In an ideal world, both systems programming and embedded would have the same intolerance of code failure.
The JSF C++ Coding Standardsstandard doesn't say why. It just says that "Rationale: Tool support is not adequate at this time."
I'll offer another opinion: Lockheed did not want to preclude using Green Hills Software as the development toolkit. (Lockheed did eventually choose Green Hills for the development platform.) Green Hills has historically taken a dim look at the "more advanced features" of C++. Some of these, most notably exceptions, templates, virtual member functions, operator overloading, namespaces, multiple inheritance, and RTTI, they simply chose not to implement those features for a long time.
I don't do or understand cyclic complexity. To me it is another of those measurements that non-technical managers like to add in, like SLOC. Code review goes quite a long way towards addressing this issue.
It's a useful metric for indicating how many test cases need to be written, for indicating where the trouble spots are likely to lie, and for estimating costs of future projects with similar size and complexity to an existing one.
I don't really get why people have trouble with source code formatters.
Suppose you are charged with making a slight mod to a chunk of code. You look at the code and see that the programmer used white space to make the equal signs in a chunk of assignment statements line up vertically. So you temporarily set your IDE to auto-align on the equals sign in assignment statements. What you didn't see is that code is chock full of code like this:
Obviously the programmer thought of these as representing two sets of assignments. Your IDE doesn't. It will align all five of these statements on the equal signs. Should there be a blank line separating the two sets? That would certainly help an automated tool, but not everyone uses automated tools. I don't write code like this, but I certainly have seen it.
Another problem: You use four space indent and write switch statements like this:
Code:
switch (condition) {
case First:
do_the_first_thing();
break;
...
case Last:
do_the_last_thing();
break;
}
You are charged with maintaining some code that's indented like this:
Code:
switch (condition) {
case First:
do_the_first_thing();
break;
...
case Last:
do_the_last_thing();
break;
}
When you re-indent to suit your style, make your changes, and then convert back to the original style you will be making changes to code that you did not change.
That's just two examples. There are many more. If the original coder used an IDE, it's best to use their settings when you are modifying their code. If they used vi or emacs, you had best not use an IDE at all.
As a reviewer, I'm go to use something like git blame to see what changes you have made, and white space changes are changes. The last thing I want to see as a reviewer is a bunch of changes that aren't really changes.
#49
gmar
25
0
D H said:
The JSF C++ Coding Standardsstandard doesn't say why. It just says that "Rationale: Tool support is not adequate at this time."
I'll offer another opinion: Lockheed did not want to preclude using Green Hills Software as the development toolkit. (Lockheed did eventually choose Green Hills for the development platform.) Green Hills has historically taken a dim look at the "more advanced features" of C++. Some of these, most notably exceptions, templates, virtual member functions, operator overloading, namespaces, multiple inheritance, and RTTI, they simply chose not to implement those features for a long time.
I don't see how those opinions differ. I just did some Google-fu.
JSF++ is for hard-real time and safety-critical applications (flight control software). If a computation takes too long someone may die. For that reason, we have to guarantee response times, and we can't - with the current level of tool support - do that for exceptions. --- source: http://www.stroustrup.com/bs_faq2.html
I think we are in agreement. I didn't know he was involved in the project until I noticed he wrote "we". I guess that commerically, C++ did "need" some kind of high-profile embedded project.
D H said:
...whitespace...
I am not at all convinced by this.
If non-trivial code isn't formatted according some kind of formal standard, it is broken. We fix broken code.
Those assignments using horizontal position of the equals sign to divide them into sections: Yes, I've also seen code like that. It's plain wrong. You understandably believe it should have a blank line. I would also accept a blank line or a comment. Using automated tools to add or remove blank lines from the middle of functions is in my opinion also like reformatting comments: don't do it.
The leading whitespace in the switch: You don't have to have the same style for everything, so long as your tools can apply the correct template to the correct file, you can mix multiple nesting styles in the same project. If it *does* flag a change and cause a rebuild, it will happen only once, the first time the tools touch it, and, again, it means it was broken.
#50
voko
6,053
391
gmar said:
In my opinion, to go into more detail about JSF the 'toolset driven' reason D H quotes that they cite for disallowing exceptions is almost certainly related to the unpredictability of the execution time.
Possibly. However, I think it had more to do with the fact that exceptions require support by the compiler, the runtime library and very frequently by the OS or whatever substrate there is for execution. None of which may exist in some particularly dumb environment. Besides, whatever mechanics is used for exception may be incompatible or unavailable in certain modes (as in, for example, in Windows kernel mode at a raised interrupt request level).