Code Style - Handling Returns

N

n2xssvv g02gfr12930

Jordan said:
While writing some code, I realized I had never developed a consistent
pattern for checking errors from a method. I have two styles I jump
back and forth between, but I'm wondering which is better.

Scenario:
* In method that returns success/fail
* Call method that also returns success/fail
* Need to check return state and continue or exit outer method

I personally think Case 1 looks a little cleaner but it breaks more
than case 2. Any opinions?


Case 1:

bool flag = myFunc1( );
if( flag == false )
{
return;
}

flag = myFunc2( );
if( flag == false )
{
return;
}

// more code


Case 2:

bool flag = myFunc1( );
if( flag == true )
{
flag = myFunc2( );
if( flag == true )
{
flag = myFunc3( );
if( flag == true )
{
// continue code
}
}
}
Personally I prefer to return an enum value which can be given names
relevant to the result, and subsequent handling with a switch/case. This
is also useful within class definitions to help clarify the code purpose
and scope, (vital in OOAD).

JB
 
Z

zhaokai115

try this

do {
bool flag = myFunc1( );
if (!flag)
{
break;
}

flag = myFunc2( );
if (!flag)
{
break;
}

...
return TRUE;
} while (0);

.... // handle errors or free resources
return FALSE;


Jordan 写é“:
 
P

Paul

In my opinion the only downside to case 1 is future proofing. Clearly
the examples you have given are simple beyond real life examples. In
reality, the code would be much longer and more complex. My coding
style refuses the use of unnecessaery 'return' and/or 'break' or
'continue'.

Imaging addressing this code a few years down the line. We need to
change the code. Say both func1 and func2 must have a file opened while
they execute. Now try to add that enhancement to each of the above and
see how much longer it takes you and how many potential errors you
leave behind.

I will generally use case 2 except in unusual situations.

Paul
 
J

Jordan

Paul,

That is a good point too. The example given is just to setup a basic
framework for suggestion. Maybe the circumstances of the question are
not good to begin with.

Let's take the example of a COM client. In COM, all methods return an
HRESULT (no exceptions here). The value of the HRESULT must be tested
before proceeding forward. When working with a COM API, it is often
common to make many linear calls to COM interface methods to initialize
an object before processing. In this case, if one of the
initialization methods errors, the parent method should bail. Using
'returns' is essential.

However, I absolutley agree that 'break' and 'continue' should be
avoided as much as possible. I have never liked those keywords - leads
to unstructured code.
 
J

Jordan

Well, the more I think about it, my last statement wasn't completely
true - "The use of 'returns' is essential'. The nested success gate in
case 2 would still work.
 
J

Jordan

While we are talking about it, exceptions are not ideal for basic
program control because they introduce program overhead and consume a
large amount of memory for processing. This typically is not desired
for C++ applications since we write C++ apps for performance. If you
move to another platform such as .NET, exception handling is incredidly
slow.

As far as *how* errors are handled, I like enums and mapping those to
strings. They are fast, easy to read, and consistent. True, exception
handling enhanced program readability, but ultimatley they are designed
for handling an applications "last breath" before death.
 
P

Paul

Jordan,
I would ALWAYS use the nested form and have been for too many years to
mention. Many times I have taken apart code of the first form and used
formal techniques to convert it to the second form, only to find the
error I sought and several others. This style will almost always find
and make clear and obvious many logic errors in the code. Method 1 is
only obfuscation with a 'you dont have to type so much' up side.

However, everyone must create their own style from their own wisdom.
Some minds would be quite capable of dealing with style 1 code. Mine
stumbles!

In my opinion, the use of returns should be avoided whenever possible,
as with break, continue and goto.

Paul
 
G

Geo

Victor said:
Peter said:
[...]
Another track in this thread: How would instead like to use exception
handling? E.g.:

try {
myFunc1(); // Which may throw an exception if you desing it so.
myFunc2(); // Which may throw anonther exception.
myFunc3(); // Which may throw yet anonther exception.
// ... and so on
} catch(std::exception&) {
}

Or some variant thereof.

There is a school of thought out there that strongly discourages
using exception handling to handle something that is normal. If the
purpose is to detect a normal condition (flag is set to false is not
an exceptional situation) and bail out earlier, exceptions may not be
the right tool.

I am sure you can find more on error code checking versus exception
handling in the archives.

V


Am I missing something here ? I thoght the flag was onlyset false
because an error had been detected, so it wasn't a "normal" condition ?

I'm a big fan of exceptions, use them all the time, I thought the whole
point of them was to get away from having to test return values all
over the place, and delegate error handling to the most appropriate
level in the code. Obviously it depends what you consider an error and
a "normal" condition.
 
V

Victor Bazarov

Geo said:
Victor said:
Peter said:
[...]
Another track in this thread: How would instead like to use exception
handling? E.g.:

try {
myFunc1(); // Which may throw an exception if you desing it so.
myFunc2(); // Which may throw anonther exception.
myFunc3(); // Which may throw yet anonther exception.
// ... and so on
} catch(std::exception&) {
}

Or some variant thereof.

There is a school of thought out there that strongly discourages
using exception handling to handle something that is normal. If the
purpose is to detect a normal condition (flag is set to false is not
an exceptional situation) and bail out earlier, exceptions may not be
the right tool.

I am sure you can find more on error code checking versus exception
handling in the archives.

V



Am I missing something here ?

Seems like a whole lot.
> I thoght the flag was onlyset false
because an error had been detected, so it wasn't a "normal" condition ?

Examples of errors:
- wrong input from the user;
- absence of a file on the external storage;
- too many sockets open at once;
- timeout while waiting for input;

Those all are _normal_ situations, happening from time to time depending
on the circumstances. Those are definitely _not_ exceptional situations
(look up "exceptional" in a dictionary). Such "errors" prevent most of
the programs to continue doing what they are asked/designed to do and need
to be handled. They are often just states of the program which simply
lead to different results than "normal", error-free, situations.

The whole point of exception handling is that if something happens down
the road (deeper in the call stack) that we do not _foresee_, try to do
our best about it. If we can _predict_ that in some course of actions it
might happen, it's not an exception.
I'm a big fan of exceptions, use them all the time, I thought the whole
point of them was to get away from having to test return values all
over the place, and delegate error handling to the most appropriate
level in the code. Obviously it depends what you consider an error and
a "normal" condition.

I think you've been duped into thinking that exceptions are a regularly
occurring thing. I strongly advise read more on the topic and review your
convictions.

V
 
J

Jordan

Paul,

I agree. I think I better understand what you are saying. I've never
liked using 'return' statements in code, but I questioned if having
deep nestings hurt readability. However, I feel 'return' can almost be
as bad as 'goto' and should be avoided.

These are good thoughts. Thanks for everyone's input on this matter.
Let me know if you all have anymore suggestions.
 
N

Neil Cerutti

Paul,

I agree. I think I better understand what you are saying.
I've never liked using 'return' statements in code, but I
questioned if having deep nestings hurt readability. However,
I feel 'return' can almost be as bad as 'goto' and should be
avoided.

I would say, use the style (nested returns, et al) that makes
what you're doing clear. If the code is easy to understand, I
wouldn't quibble about a nested return or breaks.
 
G

Geo

Victor said:
Geo said:
Victor said:
Peter Jansson wrote:

[...]
Another track in this thread: How would instead like to use exception
handling? E.g.:

try {
myFunc1(); // Which may throw an exception if you desing it so.
myFunc2(); // Which may throw anonther exception.
myFunc3(); // Which may throw yet anonther exception.
// ... and so on
} catch(std::exception&) {
}

Or some variant thereof.

There is a school of thought out there that strongly discourages
using exception handling to handle something that is normal. If the
purpose is to detect a normal condition (flag is set to false is not
an exceptional situation) and bail out earlier, exceptions may not be
the right tool.

I am sure you can find more on error code checking versus exception
handling in the archives.

V



Am I missing something here ?

Seems like a whole lot.
I thoght the flag was onlyset false
because an error had been detected, so it wasn't a "normal" condition ?

Examples of errors:
- wrong input from the user;
- absence of a file on the external storage;
- too many sockets open at once;
- timeout while waiting for input;

Those all are _normal_ situations, happening from time to time depending
on the circumstances. Those are definitely _not_ exceptional situations
(look up "exceptional" in a dictionary). Such "errors" prevent most of

Why look up "exceptional", maybe you should look up "exception" or
maybe "except" !!!!
the programs to continue doing what they are asked/designed to do and need
to be handled. They are often just states of the program which simply
lead to different results than "normal", error-free, situations.

The whole point of exception handling is that if something happens down
the road (deeper in the call stack) that we do not _foresee_, try to do
our best about it. If we can _predict_ that in some course of actions it
might happen, it's not an exception.


I think you've been duped into thinking that exceptions are a regularly
occurring thing. I strongly advise read more on the topic and review your
convictions.

V


If I've been duped then it's been by Bjarne Stroustrup, C++ PL 3rd
Edition 14.1.1, last paragraph.

Looks like your definiton of exception is too dogmatic and restrictive,
you pays your money.....
 
D

deane_gavin

Victor said:
Examples of errors:
- wrong input from the user;
- absence of a file on the external storage;
- too many sockets open at once;
- timeout while waiting for input;

Those all are _normal_ situations, happening from time to time depending
on the circumstances. Those are definitely _not_ exceptional situations
(look up "exceptional" in a dictionary). Such "errors" prevent most of
the programs to continue doing what they are asked/designed to do and need
to be handled. They are often just states of the program which simply
lead to different results than "normal", error-free, situations.

The whole point of exception handling is that if something happens down
the road (deeper in the call stack) that we do not _foresee_, try to do
our best about it. If we can _predict_ that in some course of actions it
might happen, it's not an exception.

What about things that we do forsee and that we want to handle at this
level but that are actually detected deeper down in the call stack?

void foo
{
// do stuff
some_variable1 = helper1(params);
// do stuff
some_variable2 = helper2(params);
// do stuff
some_variable3 = helper3(params);
// do stuff
}

Suppose each of those helper functions has a similar structure, i.e.
each helper calls other functions to help it do its work. And suppose
each of those other functions calls some more. So the call stack goes a
few levels deep, with several functions at the lowest level. Some of
the functions, at every level, have non-void return types because they
need to return something to their caller. Now suppose there are some
functions at the lowest level that can detect "errors" to which the
appropriate response is to cancel the operation foo is performing. I
would handle that by throwing exceptions from the deep down functions
and catching them in foo.

The alternative is to introduce a set of error codes. Every function at
every level now has to check for errors in a return value. Previously
returned values have to become out parameters. I have a maintenance and
robustness problem because it's too easy to forget or not bother to
check an error code. The code is more cluttered with error code
checking and out parameters.

Using exceptions avoids all of those problems. Why is it relevant
whether the "errors" are things that I happen to have forseen? In fact,
I'm not really sure what it could mean to write code to handle a
situation I hadn't forseen.

Gavin Deane
 
R

roberts.noah

Victor said:
Those all are _normal_ situations, happening from time to time depending
on the circumstances. Those are definitely _not_ exceptional situations
(look up "exceptional" in a dictionary).

ex·cep·tion·al Audio pronunciation of "exceptional" ( P )
Pronunciation Key (k-spsh-nl)
adj.

1. Being an exception; uncommon.
2. Well above average; extraordinary: an exceptional memory. See
Usage Note at exceptionable.
3. Deviating widely from a norm, as of physical or mental ability:
special educational provisions for exceptional children.

ex·cep·tion Audio pronunciation of "exception" ( P ) Pronunciation
Key (k-spshn)
n.

1. The act of excepting or the condition of being excepted;
exclusion.
2. One that is excepted, especially a case that does not conform to
a rule or generalization.
3. An objection or a criticism: opinions that are open to exception.
4. Law. A formal objection taken in the course of an action or a
proceeding.
If we can _predict_ that in some course of actions it
might happen, it's not an exception.

I don't see anything in the definition of exceptional that states it
could not be predicted to be possible.

IMHO #2 of exception gives a good idea of its purpose in programming:
"...a case that does not conform to a rule or generalization."

So (by def of "exceptional") change your statement to: "If we can
_predict_ that in some *normal* course of actions it might happen, it's
not an exception."

For example, sometimes it is normal to hit EOF on a stream, such as
when reading a file. Other times you could consider it exceptional to
hit an EOF before hearing a terminate from that stream.
 
K

Kai-Uwe Bux

Victor said:
The whole point of exception handling is that if something happens down
the road (deeper in the call stack) that we do not _foresee_, try to do
our best about it. If we can _predict_ that in some course of actions it
might happen, it's not an exception.

I beg to differ. For instance, new() can fail to allocate memory. This is
nothing out of the ordinary and we do forsee that this might happen from
time to time. The point of new() throwing instead of returning a special
value is not because of unpredictability but because we want the
flexibility to postpone handling of the error.


Best

Kai-Uwe Bux
 
J

Jordan

This is splitting hairs pretty thin.
From what I understand, exceptions would be something more of a
"system-level" manner (e.g. divide by zero, unable to allocate memory,
pointer out of range, etc.).

I believe the true debate is not over the finite boundaries of
exceptions but that exceptions should not be used for routine program
control. In other words, check for ERRORS and not STATES with
exception handling.

Does this make sense?

For example, a function that opens a file in a directory passed in as a
parameter should not throw an exception if the file doesn't exist.
This would be better suited for a 'condintional' error return.
However, if the API call that opens that file barfs, an exception
should be thrown.
 
K

Kai-Uwe Bux

Jordan said:
This is splitting hairs pretty thin.

Please quote what you are refering to. If you are actually accusing me of
splitting hairs, be more specific.
"system-level" manner (e.g. divide by zero, unable to allocate memory,
pointer out of range, etc.).

Divide by zero is unlikely to throw and so is pointer out of range. Those
conditions will usually yield undefined behavior.
I believe the true debate is not over the finite boundaries of
exceptions but that exceptions should not be used for routine program
control. In other words, check for ERRORS and not STATES with
exception handling.

Does this make sense?

Yes, in that it is a meaningful statement. It just so happens to be false or
at least a matter of opinion where reasonable can disagree. Throw-catch is
a flow control construct doing stack unwinding so that that it allows us to
break out of arbitrarily deep function call contexts. How you want to use
it, is up to you. I do not consider the distinctions of errors vs. states
(introduced by you) or predictable vs. unpredictable (suggested by Victor)
as good guidelines. I usually ask myself something like: do I want to
unwind the stack or can I handle this condition locally?
For example, a function that opens a file in a directory passed in as a
parameter should not throw an exception if the file doesn't exist.
This would be better suited for a 'condintional' error return.
However, if the API call that opens that file barfs, an exception
should be thrown.

Why? What about a constructor that constructs a file object from a file name
-- should that not throw if the file does not exists? Would you rather have
a half-constructed ill-fated object hanging around that you might not even
be able to destroy properly? In the contect of RAII, failure to acquire a
resource seems to be a good candidate for a throw() regardless of the cause
for the failure.


Best

Kai-Uwe Bux
 
D

deane_gavin

Jordan said:
For example, a function that opens a file in a directory passed in as a
parameter should not throw an exception if the file doesn't exist.

For me, the decision about how to handle that case is simple. "Am I
going to handle this situation locally?". If not, then I will avoid the
clutter of return codes (which are also at risk of not being checked)
and out parameters and throw an exception.

Gavin Deane
 
R

Ron Natalie

Jordan said:
As far as *how* errors are handled, I like enums and mapping those to
strings. They are fast, easy to read, and consistent. True, exception
handling enhanced program readability, but ultimatley they are designed
for handling an applications "last breath" before death.

Mid block gotos and returns violate structured programming. If
your constructs are small and their clearly marked you might decide
to forgive the structure violations, but you'll have to make that
decision.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,276
Latest member
Sawatmakal

Latest Threads

Top