I've seen many examples and this is getting me more than curious
The two examples are the following :
Having return;at the end of a void function, this is flat out ridiculous.
Using return;in the middle of a function to break out of it. I don't like it.
The following example might clarify the second case (the first one being obvious):
- SomeMethodThatReturnsSomethingOrNot(var param1){
if (param1 == null){
CallThisMethod();
return;
}
CallThisOtherMethod(param1);
}
To a lot of people, this is fine and clear. To me, it is acceptable at best.
Why not simply using an if else? You avoid the need to return nothing in the middle of the code, it doesn't decrease readability, and, well, I don't know what else to say, it just looks like a better practice to me.
- SomeMethodThatReturnsSomethingOrNot(var param1){
if (param1 == null){
CallThisMethod();
}else{
CallThisOtherMethod(param1);
}
}
Now I'd like to emphasize the simplicity of the example here, I know somethign sexier could be made but lets just pretend its something a bit more complex than a null check, that requires the same kind of if-returninsteadof if-else technique.
So, what are everyone's thoughts?
I've been strongly against returning something when the method is either void, or when I don't actually want to return anything. If I end up in that situation, I like to rethink my architecture because it shouldn't happen.
Am I completely wrong/right or is there some discussing space here?
You might be interested in looking into the subject of SESE (single entry, single exit) and Dijkstra's thoughts on the subject which kind of prompted this style.
It's worth noting though that Dijkstra's thoughts are often misunderstood. He was advocating practices during an era where a lot of people were writing code in straight assembly. In assembly, you're often allowed to jump from any instruction to any other. That's where the notion of "single-entry" comes from: it's extremely confusing to jump from one function into the middle of another.
"Single-exit" is often misinterpreted to mean exiting a function from only one place. It actually meant exiting a function to only one place. It becomes extremely confusing if you returned out of a function to a place other than the site in which it was called.
Nevertheless, a lot people today continue to think of "single-exit" to mean, "exit from only one place in a function", and advocates often promote the style you're suggesting.
I won't go into which one is better or worse. It's inevitably going to be subjective. But there are some things worth thinking about.
Explicit Cleanup
The idea of exiting from only one place in a function was largely popularized during eras that required explicit cleanup in many functions with respect to their resources -- something like this:
function f()
allocate_resources()
...
deallocate_resources()
end
We can see if we introduced any kind of early return statement in such a function that we could easily forget to deallocate the resources and end up with some kind of resource leak. In these cases, the suggestion to favor return statements only at the end of a function become significantly more useful to prevent human errors.
Exception-Handling
Exception-handling is now a common feature in many modern languages. With exception-handling, there can be implicit exits all over a function. Example:
function f()
list = create_list() -- could throw
list.insert(123) -- could throw
connect_to_server() -- could throw
if x == 0 then
add_some_widget() -- could throw
end
end
In these cases, any line of code could have an implicit exit point from the function as a result of an exception being thrown. As a result, it's impossible to make the control flow totally predictable. There too, comes an inevitable need for automated resource management where it's up to the compiler (or garbage collector) to clean up resources automatically, not up to the developer to do it manually, because it becomes too impractical to do it manually with so many implicit exit points in a function.
Conclusion
So these are some of the considerations to make. I'm personally in the middle-lower end of the spectrum (if "low" means putting returns anywhere, and "high" means only at the bottom). But it's all up to you where you find your comfort zone, and what kind of code you find easiest to understand and maintain.
In my humble opinion we could go cross-eyed trying to analyze the merits of exactly how a function is written down to every single line of code, but I'd have to appeal to a pragmatic sort of view of like just test it well, make sure the interface and documentation is clear, make sure the implementation maybe passes a basic litmus test of not causing people's brains to explode, and then ship it.
I have following requirement:
Adding text at the entry and exit point of any function.
Not altering the source code, beside inserting from above (so no pre-processor or anything)
For example:
void fn(param-list)
{
ENTRY_TEXT (param-list)
//some code
EXIT_TEXT
}
But not only in such a simple case, it'd also run with pre-processor directives!
Example:
void fn(param-list)
#ifdef __WIN__
{
ENTRY_TEXT (param-list)
//some windows code
EXIT_TEXT
}
#else
{
ENTRY_TEXT (param-list)
//some any-os code
if (condition)
{
return; //should become EXIT_TEXT
}
EXIT_TEXT
}
So my question is: Is there a proper way doing this?
I already tried some work with parsers used by compilers but since they all rely on running a pre-processor before parsing, they are useless to me.
Also some of the token generating parser, which do not need a pre-processor are somewhat useless because they generate a memory-mapping of tokens, which then leads to a complete new source code, instead of just inserting the text.
One thing I am working on is to try it with FLEX (or JFlex), if this is a valid option, I would appreciate some input on it. ;-)
EDIT:
To clarify a little bit: The purpose is to allow something like a stack trace.
I want to trace every function call, and in order to follow the call-hierachy, I need to place a macro at the entry-point of a function and at the exit point of a function.
This builds a function-call trace. :-)
EDIT2: Compiler-specific options are not quite suitable since we have many different compilers to use, and many that are propably not well supported by any tools out there.
Unfortunately, your idea is not only impractical (C++ is complex to parse), it's also doomed to fail.
The main issue you have is that exceptions will bypass your EXIT_TEXT macro entirely.
You have several solutions.
As has been noted, the first solution would be to use a platform dependent way of computing the stack trace. It can be somewhat imprecise, especially because of inlining: ie, small functions being inlined in their callers, they do not appear in the stack trace as no function call was generated at assembly level. On the other hand, it's widely available, does not require any surgery of the code and does not affect performance.
A second solution would be to only introduce something on entry and use RAII to do the exit work. Much better than your scheme as it automatically deals with multiple returns and exceptions, it suffers from the same issue: how to perform the insertion automatically. For this you will probably want to operate at the AST level, and modify the AST to introduce your little gem. You could do it with Clang (look up the c++11 migration tool for examples of rewrites at large) or with gcc (using plugins).
Finally, you also have manual annotations. While it may seem underpowered (and a lot of work), I would highlight that you do not leave logging to a tool... I see 3 advantages to doing it manually: you can avoid introducing this overhead in performance sensitive parts, you can retain only a "summary" of big arguments and you can customize the summary based on what's interesting for the current function.
I would suggest using LLVM libraries & Clang to get started.
You could also leverage the C++ language to simplify your process. If you just insert a small object into the code that is constructed on function scope entrance & rely on the fact that it will be destroyed on exit. That should massively simplify recording the 'exit' of the function.
This does not really answer you question, however, for your initial need, you may use the backtrace() function from execinfo.h (if you are using GCC).
How to generate a stacktrace when my gcc C++ app crashes
Sometimes you need to skip execution of part of a method under certain non-critical error conditions. You can use exceptions for that, but exceptions generally are not recommended in normal application logic, only for abnormal situations.
So I do a trick like this:
do
{
bool isGood = true;
.... some code
if(!isGood)
break;
.... some more code
if(!isGood)
break;
.... some more code
} while(false);
..... some other code, which has to be executed.
I use a "fake" loop which will run once, and I can abort it by break or continue.
Some of my colleagues did not like that, and they called it "bad practice". I personally find that approach pretty slick. But what do you think?
Bad practice, it depends.
What I see in this code is a very creative way to write "goto" with less sulphur-smelling keywords.
There are multiple alternatives to this code, which can or can not be better, depending on the situation.
Your do/while solution
Your solution is interesting if you have a lot of code, but will evaluate the "exit" of this processing at some limited points:
do
{
bool isError = false ;
/* some code, perhaps setting isError to true */
if(isError) break ;
/* some code, perhaps setting isError to true */
if(isError) break ;
/* some code, perhaps setting isError to true */
}
while(false) ;
// some other code
The problem is that you can't easily use your "if(isError) break ;" is a loop, because it will only exit the inner loop, not your do/while block.
And of course, if the failure is inside another function, the function must return some kind of error code, and your code must not forget to interpret the error code correctly.
I won't discuss alternatives using ifs or even nested ifs because, after some thinking, I find them inferior solutions than your own for your problem.
Calling a goto a... goto
Perhaps you should put clearly on the table the fact you're using a goto, and document the reasons you choose this solution over another.
At least, it will show something could be wrong with the code, and prompt reviewers to validate or invalidate your solution.
You must still open a block, and instead of breaking, use a goto.
{
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
while(/* etc.*/)
{
// etc.
for(/* etc.*/)
{
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
}
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
}
// etc.
}
MY_EXIT:
// some other code
This way, as you exit the block through the goto, there is no way for you to bypass some object constructor with the goto (which is forbidden by C++).
This problem solves the process exiting from nested loops problem (and using goto to exit nested loops is an example given by B. Stroustrup as a valid use of goto), but it won't solve the fact some functions calls could fail and be ignored (because someone failed to test correctly their return code, if any).
Of course, now, you can exit your process from multiple points, from multiple loop nesting depth, so if it is a problem...
try/catch
If the code is not supposed to fail (so, failure is exceptional), or even if the code structure can fail, but is overly complex to exit, then the following approach could be clearer:
try
{
// All your code
// You can throw the moment something fails
// Note that you can call functions, use reccursion,
// have multiple loops, etc. it won't change
// anything: If you want to exit the process,
// then throw a MyExitProcessException exception.
if(/* etc. */)
{
// etc.
while(/* etc.*/)
{
// etc.
for(/* etc.*/)
{
// etc.
if(/*some failure condition*/) throw MyExitProcessException() ;
// etc.
}
// etc.
callSomeFunction() ;
// the function will throw if the condition is met
// so no need to test a return code
// etc.
}
// etc.
}
// etc.
}
catch(const MyExitProcessException & e)
{
// To avoid catching other exceptions, you should
// define a "MyExitProcessException" exception
}
// some other code
If some condition in the code above, or inside some functions called by the code above, is not met, then throw an exception.
This is somewhat weightier than your do/while solution, but has the same advantages, and can even abort the processing from inside loops or from inside called functions.
Discussion
Your need seems to come from the fact you can have a complex process to execute (code, functions calls, loops, etc.), but you want to interrupt it over some condition (probably either failure, or because it succeeded sooner than excepted). If you can rewrite it in a different way, you should do it. But perhaps, there is no other way.
Let's assume that.
If you can code it with a try/catch, do it: To interrupt a complex piece of code, throwing an exception is the right solution (the fact you can add failure/success info inside your exception object should not be underestimated). You will have a clearer code after that.
Now, if you're in a speed bottleneck, resolving your problem with thrown exceptions as an exit is not the fastest way to do it.
No one can deny your solution is a glorified goto. There won't be a goto-spaghetti code, because the do/while won't let you do that, but it is still a semantic goto. This can be the reasons some could find this code "bad": They smell the goto without finding its keyword clearly.
In this case (and in this performance, profiled-verified) case only, your solution seems Ok, and better than the alternative using if), but of lesser quality (IMHO) than the goto solution which at least, doesn't hide itself behind a false loop.
Conclusion
As far as I am concerned, I find your solution creative, but I would stick to the thrown exception solution.
So, in order of preference:
Use try/catch
Use goto
Use your do/while loop
Use ifs/nested ifs
You're pretty much just disguising a "goto" as a fake loop. Whether you like gotos or not, you'd be just as far ahead using a real undisguised goto.
Personally, I'd just write it as
bool isGood = true;
.... some code
if(isGood)
{
.... some more code
}
if(isGood)
{
.... some more code
}
Why use a fake loop? You can do the same thing with a method and it probably won't be considered a "bad practice" as it is more expected.
someMethod()
{
.... some code
if(!isGood)
return;
.... some more code
if(!isGood)
return;
.... some more code
}
You have complicated non-linear control flow inside a difficult to recognize idiom. So, yes, I think this technique is bad.
It might be worthwhile to spend sometime trying to figure out if this can be written a little nicer.
This is convoluted and confusing, I would scrap it immediately.
Consider this alternative:
private void DoSomething()
{
// some code
if (some condition)
{
return;
}
// some more code
if (some other condition)
{
return;
}
// yet more code
}
Also consider breaking up the code above into more than one method.
public bool Method1(){ ... }
public bool Method2(){ ... }
public void DoStuff(){
bool everythingWorked = Method1() && Method2();
... stuff you want executed always ...
}
The reason why this works is due to something called short circuit logic. Method2 won't be called if Method1 returns false.
This also has the additional benefit that you can break your method into smaller chunks, which will be easier to unit test.
What you're trying to do is non-local failure recovery. This is what goto is for. Use it. (actually, this is what exception handling is for -- but if you can't use that, 'goto' or 'setjmp/longjmp' are the next best thing).
This pattern, the if(succeeded(..)) pattern, and 'goto cleanup', all 3 are semantically and structurally equivalent. Use whichever one is most common in your code project. There's much value in consistency.
I would caution against if(failed(..)) break; on one point in that you're producing a surprising result should you try to nest loops:
do{
bool isGood = true;
.... some code
if(!isGood)
break;
.... some more code
for(....){
if(!isGood)
break; // <-- OOPS, this will exit the 'for' loop, which
// probably isn't what the author intended
.... some more code
}
} while(false);
..... some other code, which has to be executed.
Neither goto cleanup nor if(succeeded(..)) have this surprise, so I'd encourage using one of these two instead.
Basically you just described goto. I use goto in C all the time. I don't consider it bad, unless you use it to emulate a loop (never ever do that!). My typical usage of goto in C is to emulate exceptions (C has no exceptions):
// Code
if (bad_thing_happened) goto catch;
// More code
if (bad_thing_happened) goto catch;
// Even more code
finally:
// This code is executed in any case
// whether we have an exception or not,
// just like finally statement in other
// languages
return whatever;
catch:
// Code to handle bad error condition
// Make sure code tagged for finally
// is executed in any case
goto finally;
Except for the fact that catch and finally have opposite order, I fail to see why this code should be BAD just because it uses goto, if a real try/catch/finally code works exactly like this and just doesn't use goto. That makes no sense. And thus I fail to see why your code should be tagged as BAD.
Refactor. The clean solution will in most cases be to split this code out into a smaller helper function, from which you can return, rather than breaking out of your not-actually-a-loop.
Then you can substitute your break's for return's, and now people can immediately make sense of your code when reading it, instead of having to stop and wonder why you made this loop which doesn't actually loop.
Yes, I'd say that simply because it doesn't behave as the reader would expect, it's a bad practice. The principle of least surprise, and so on. When I see a loop, I expect it to loop, and if it doesn't, I have to stop and wonder why.
I have no problem with that as long as the code is readable.
I have used this idiom for years. I find it preferable to the similar nested or serial ifs , the "goto onError", or having multiple returns. The above example with the nested loop is something to watch out for. I always add a comment on the "do" to make it clear to anyone new to the idiom.
For better or worse, I have used the construct in a few places. The start of it is clearly documented, though:
/* This is a one-cycle loop that simplifies error handling */
do
{
...modestly complex code, including a nested loop...
} while (0);
This is in C, rather than C++ - so exceptions aren't an option. If I were using C++, I would consider seriously using exceptions to handle exceptions. The repeated test idiom suggested by Jeremy is also reasonable; I have used that more frequently. RAII would help me greatly, too; sadly, C does not support that easily. And using more functions would help. Handling breaks from inside the nested loop is done by repeated test.
I would not classify it as a great style; I would not automatically categorize it as "BAD".
It depends on what the alternatives are. You have to admit that the code you posted is somewhat ugly. I wouldn't say it's clear. It's a kind of a hack. So if using some other coding solution would be worse, then ok. But if you have better alternative, don't let the excuse "it's good enough" comfort you.
Its a very strange idiom. It uses a loop for something its not intended and may cause confusion. I'd imagine this is going to span more than one page, and it would be a surprise to most people that this is never run more than once.
How about using more usual language features like functions?
bool success = someSensibleFunctionName();
if(success)
{
...
}
someCommonCodeInAnotherFunction();
I would consider this bad practice. I think it would be more idiomatic, and generally clearer if you made this a function and changed the breaks to returns.
Split your code into smaller chunks of functional elements - so you could split the above into a function that returns instead of breaking.
I don't know if the above is bad practice but it's readability is a little off and may be confusing to others who might have to maintain the source.
To me what you are doing is bad in so many ways. The loop can be replaced by putting that code in a method.
I personally believe that if you have to put a ! in front of your conditions then you are looking for the wrong thing. For readability make your boolean match what you are checking for. You are really checking if there is an error or some bad condition, so I would prefer:
If (isError)
{
//Do whatever you need to do for the error and
return;
}
over
If (!isGood)
{
//Do something
}
So check for what you really want to check for and keep the exception checks to a minimum. Your goal should be readibility over being tricky. Think of the poor soul that is going to have to come along and maintain your code.
One of the first things I worked on 28 years ago was a Fortran program that always needed to check if there was a graphics device available. Someone made the grand decision to call the boolean for this LNOGRAF, so if there was a graphics device available this would be false. I believe it got set this way because of a false efficiency, the check for the device returned zero if there was a graphics device. Throughout the code all the checks were to see if the graphics device was available. It was full of:
If (.NOT. LNOGRAF)
I don't think there was a single:
If (LNOGRAF)
in the program. This was used in mission planning software for B-52's and cruise missiles. It definitely taught me to name my variables for what I'm really checking for.
What about a functional approach?
void method1()
{
... some code
if( condition )
method2();
}
void method2()
{
... some more code
if( condition )
method3();
}
void method3()
{
... yet more code
if( condition )
method4();
}
I would say your solution can be the right solution, but it depends. Paul Tomblin has posted an answer that is better (a series of if tubes) ... if it can be used.
Paul's solution cannot be used when there are expensive object initializations along the way through your loop. If the created objects are used in later steps, the do while (0) solution is better.
That said, variable naming should be improved. Additionally, why reuse the "escape" variable so much? Instead trap each individual error condition explicitly and break the loop so that it is obvious what causes the break out at each point.
Someone else suggested using function calls. Again, this may not be an ideal decomposition if it adds unneeded complexity to the function calls due to the number of args that might be passed at any given step.
Others have suggested this is a difficult to understand idiom. Well, first you could put a comment as suggested at the top of the loop. Second, do-while(0) is a normal and common idiom in macros that all C programmers should recognize immediately, so I just don't buy that.
If your code is doing something other than the plain meaning of the constructs in place, it's a good sign you've ventured into "cute" territory.
In this case you have a "loop" that will only run once. Any reader of the code will need to do a double-take to figure out what's going on.
If the case where it isn't "good" is truly exceptional, then throwing exceptions would be the better choice.
First, if you just want an answer to whether this code structure or idiom is "bad", I would think it is. However, I think this is a symptom of bad decomposition rather than whether the code you have is "good" or "bad".
I would think much better analysis and refactoring will have to be done to be able to further address the source of the problem, rather than looking just at the code. If you can do something like:
if (condition1(...) && condition2(...) && condition3(...) && ... && conditionN(...)) {
// code that ought to run after all conditions
};
// code that ought to run whether all conditions are met or not
Then I think it would be more "readable" and more idiomatic. This way, you can make functions like:
bool conditionN(...) {
if (!real_condition) return false;
// code that ought to run
return true;
};
You get the benefit of better decomposition and help from the compiler to produce the necessary short-circuitry that &&'s will bring. The compiler might even in-line the code in the functions to produce better code than if you would doing the hand-coded loop.
You can use exceptions for that, but exceptions generally are not recommended in normal application logic, only for abnormal situations.
Nothing's wrong with using exceptions. Exceptions are part of application logic. The guideline about exceptions is that they should be relatively rare at run time.
I think that there is nothing basically wrong with the technique. I think that I would make sure that the bool is named something more descriptive than isGood. Although, now that I look at it, why would it not work to put all the code that is in the loop into a single if(!isGood) block? The loop only executes once.
If splitting code between if(!isGood) break; into separate functions, one can end up with dozens of functions containing of just a couple of lines, so that doers not simplify anything. I could not use return because I am not ready to leave the function, there is still stuf I want to do there.
I accept that probably I should just settle for separate if(isGood) {...} condition for every code part which I want to execute, but sometimes that would lead to A LOT of curly braces. But I guess I accept that people does not really like that type of construction, so conditions for everything winds! Thanks for your answers.
A meta comment:
When you're coding, your goal should be clear, maintainable code first. You should not give up legibility on the altar of efficiency unless you profile and prove that it is necessary and that it actually improves things. Jedi mind tricks should be avoided. Always think that the next guy to maintain your code is a big mean psychopath with your home address. Me, for instance.
I think I'd have to agree with your colleagues just because of readability, it's not clear atfirst glance what you are trying to accomplish with this code.
Why not just use
if(isGood)
{
...Execute more code
}
?
I think people aren't being honest here.
If I, as your team lead, would see code like this you'd be up for a little one on one, and flagged as a potential problem for the team as that piece of code is particularly horrid.
I say you should listen to your colleagues and rewrite it following any of the suggestions posted here.
This is what exceptions are for. You can't continue the logic because something went wrong. Even if recovery is trivial, it is still an exception. If you have a really good reason for not using exceptions, such as when you program in a language that does not support them, then use conditional blocks, not loops.