Salam All,
This is a c++ programming post/question. So, if you're not a programming geek, please ignore gracefully :-)
I'm looking for advice on choosing a simple & elegant programming style for a certain type of functions. I will first explain the function, and then list several solutions I've seen (and don't totally like so far), and then I'll keep it open for people to post back their suggested answers.
The Function (i want to write)The function simply has several statements to execute in order. Each statement may return an error code. The statements must be called in order, and if
any fails,
none of the rest must execute. The function also has initialization & clean up code that must run (whether the statements fail or not).
How to write this function in an elegant readable style that would allow future additions & modifications easily?
Following are several solutions I've seen. However, there's something I do not like about each. My question is... do you know of different method that would avoid any of my dislikings?
Style #1, if-else-if, exampleint TheElegantFunction () {
/*** init-code ***/
int rc = 0; //return value. 0 means no error
mutex.get();
/*** the statements s1, s2, & s3 ***/
if (0 != (rc == s1())) {
} else if (0 != (rc == s2())) {
} else if (0 != (rc == s3())) {
} else {
//we were successful
}
/*** clean up ***/
mutex.release();
return rc;
}
advantages: 1- no code repetition
2- one-exit-point for the function
3- compact code (each statement takes 1 line)
disadvantages:1- not very readable (sequential code does not belong to the if-conditional-expression)
2- what to do with non-error-returning statements, or addign-statements
3- placing those statements in else {} will force creating several levels of nested else { if... }
Style #2, if-error, example int TheElegantFunction () {
/*** init-code ***/
int rc = 0; //return value. 0 means no error
mutex.get();
/*** the statements s1, s2, & s3 ***/
rc = s1();
if (rc != 0) {
/*** clean up ***/
mutex.release()
return rc;
}
rc = s2();
if (rc != 0) {
/*** clean up ***/
mutex.release()
return rc;
}
rc = s3();
if (rc != 0) {
/*** clean up ***/
mutex.release()
return rc;
}
/*** clean up ***/
mutex.release();
return rc;
}
advantages: 1- readable
2- easy
disadvantages: 1- you have to repeat the clean up code for every single statement
2- multiple exit points for the function - can be confusing to follow the logic
Style #3, goto-solution, example int TheElegantFunction () {
/*** init-code ***/
int rc = 0; //return value. 0 means no error
mutex.get();
/*** the statements s1, s2, & s3 ***/
rc = s1();
if (rc != 0) goto end;
rc = s2();
if (rc != 0) goto end;
rc = s3();
if (rc != 0) goto end;
end:
/*** clean up ***/
mutex.release();
return rc;
}
advantages: 1- readable
2- one function exit point
3- compact
4- no repetition
disadvantages: 1- the frowned-upoen, spagetti-programming, goto statement!
2- the goto can mask the logic and make the function not very readable - especially if there are loops
Style #4, my-dream-language, example
int TheElegantFunction () {
/*** init-code ***/
int rc = 0; //return value. 0 means no error
mutex.get();
conditional_block (rc == 0 /* exit block when expression doesn't hold */) {
/*** the statements s1, s2, & s3 ***/
rc = s1();
rc = s2();
rc = s3();
}
/*** clean up ***/
mutex.release();
return rc;
}
advantages: 1- (I think) readable & elegant & clear logic-flow
2- no code-repetition
3- one entrance, one exit for the function
disadvantages: 1- imaginary (maybe a nice C# v3.0 feature? hint hint ;-))
so what do you guys think? do you know of a nice style of write such common-functions?