What is a good return value for a method? Think of a method that deletes a
license-plate number from a database:
void deleteFromDatabase(string lpn) { [...] } How will you
know if the operation was successful? Perhaps connecting to the database
failed? Then the license-plate number will still be in the database while
you (or your code's logic) assumes it is not. void is definitely
not a good return value.
Quite common is boolean deleteFromDatabase(string lpn) { [...] },
with the convention that true means that the operation succeeded,
whereas false indicates failure. This is better.
However, this is rarely expressed with an explicit boolean
return type; instead, int is used, relying on the implicit
conversion of integers into bools that the C++ standard provides. The
definition of which integers constitute false and which
true can be found in [1] (p. 71):
"nonzero integers convert to true and 0 converts to
false".
This allows constructs like
if (deleteFromDatabase("S12345F")) { [...] } which
is completely legal code, although perhaps not the most legible one. To
prevent the usage of such constructs, some people revert the logic so that
0 indicates success and all other values indicate an error.
Another reason to revert the logic so that 0 indicates success might be
to mimic the behaviour of shell commands.
The third reason is more practical in nature. If you use 0 to indicate
failure and all other integers to indicate success, all you can do is
report the fact that the function call failed, but not the reason. But
what if Fred from the other department calls and says: "I need to
know why the operation failed. With some failures, I can eliminate
the cause and try again". Which is a legitimate and sensible request,
since it will make the software more robust.
This is the main reason to use a sort of logic where 0 indicates success
and all other integers indicate failure - you then have the capability of
communicating what exactly went wrong.
You can now also use an enumeration to use plain english instead of
cryptic error codes: EDBServerUnreachable is so much more
descriptive than, say, -1.
But if you are willing to create your own return type anyway, why not go
for a class (don't use a struct; with a class you can
supply some methods like equals() that might be useful in
unit tests)? CDBOpResult deleteFromDatabase(string lpn) { [...] }
does not only leave no room for ambiguity in the interpretation of the
result (i.e. it is type safe), it offers you flexibility as well (e.g.:
CDBOpResult::getErrorMessage()).
And be sure to hide the implementation details - don't use static
attributes to communicate results: public static int
CDBOpResult::Success = 0; might lead developers to rely on
the implementation detail that CDBOpResult::Success equals
0. Instead, provide methods like
bool CDBOpResult::opSucceeded() and
bool CDBOpResult::opFailedNoConnection() to communicate the
result of the operation.