I have some programs which make heavy use of libraries with enumerations of error codes.
The kind where 0(first value of enum) is success and 1 is failure. In some cases I have my own helper functions that return bool indicating error, in other cases I bubble up the error enumeration. Unfortunately sometimes I mistake one for the other and things fail.
What would you recommend? Am I missing some warnings on gcc which would warn in these cases?
P.S. it feels weird to return an error code which is totally unrelated to my code, although I guess I could return -1 or some other invalid value.
Is it a bad idea? No, you should do what makes sense rather than following some abstract rule (the likes of which almost never cater for all situations you're going to encounter anyway).
One way I avoid troubles is to ensure that all boolean-returning function read like proper English, examples being isEmpty(), userFlaggedExit() or hasContent(). This is distinct from my normal verb-noun constructs like updateTables(), deleteAccount() or crashProgram().
For a function which returns a boolean indicating success or failure of a function which would normally follow that verb-noun construct, I tend to use something like deleteAccountWorked() or successfulTableUpdate().
In all those boolean-returning cases, I can construct an easily readable if statement:
if (isEmpty (list)) ...
if (deleteAccountWorked (user)) ...
And so on.
For non-boolean-returning functions, I still follow the convention that 0 is okay and all other values are errors of some sort. The use of intelligent function names usually means it's obvious as to which is which.
But keep in mind, that's my solution. It may or may not work for other people.
In the parts of the application that you control, and the parts that make up your external API I would say, choose one type of error handling and stick to it. Which type is less important, but be consistent. Otherwise people working on your code will not know what to expect and even you yourself will scratch you head when you get back to the code in a year or so ;)
If standardizing on a zero == error scheme, you can mix and match both enum and bool if you construct your tests like this:
err = some_func();
if !err...
Since the first enum evaluates to zero and also the success case it matches perfectly with bool error returns.
However, in general it is better to return an int (or enum) since this allows for the expansion of the error codes returned without modification of calling code.
I wouldn't say, that it's a bad practice.
There's no need to create tons of enum-s, if you just need to return true/false, and you don't have other options (and true and false are explanatory enough ).
Also, if your functions are named OK, you will have less "mistakes"
For example - IsBlaBla - expects to return true. If you have [Do|On]Reload, a reload could fail for many reasons, so enum would be expected. The same for IsConnected and Connect, etc.
IMHO function naming helps here.
E.g. for functions that return a boolean value, is_foo_bar(...), or for functions that return success or an error code, do_foo_bar(...).
Related
I have an argument with my compilation course lecturer:
In the test that was part of this course, some of the questions referred the identification and classification code segments written in C.
Each of these questions must indicate at what stage the error will expose:
a.Lexical analysis
b. Synthetic analysis
c. Semantic analysis
d. Running time (under certain conditions)
e. This is not an error.
One of the questions in this style was as follows:
Switch command that does not have the default component. For example:
switch (key){
case 1: .........
case 2: .........
case 3:..........
}
Now, in the official test solution, in the above case only option e was correct.
However, I argue that Option d cannot necessarily be rejected outright, and that it is also true.
As an argument, I showed (after the test) the following two examples to my lecturer:
1)
(from : https://cwe.mitre.org/data/definitions/478.html)
2)
(from : Should switch statements always contain a default clause?)
However, he is not yet convinced that the runtime error option is considered in this case. He said that because of the questions mentioned above, it is only for commands or snippets that are shown directly in the questions and because the code does not have the intent of the code, so in this case they are actually asking if this structure is by itself invalid, so you are denied a runtime error here (I personally do not notice any contradictory here ...).
I would be happy if you could share your views on this issue.
Your lecturer is correct.
Omitting the default case in a switch is perfectly valid code and will not directly lead to any kind of problem. It may well be exactly what the programmer intended, and do the correct thing.
Of course, it is always possible to add some code that would cause problems, but that is a problem with this added code, not with the switch per se. Code style rules like "always add a default case" may guard against certain types of programming mistakes, but not following them does not automatically cause these mistakes - it "just" requires more caution.
From a code style perspective, it is usually better to be explicit about intentionally ignoring certain cases, or to add some default handler for guarding against unexpected values, but that does not mean that omitting such a handler is always incorrect by itself.
(Note that the currently second most upvoted answer in the question you linked to yourself argues for omitting default cases that are not doing anything useful, in order to reduce clutter - I don't fully agree with that, but it is a matter of style)
I'm writing my first C library and I'm not sure which way to go about. For example a function to retrive string value from some data store can look:
int get_value(void * store, char ** result);
or
char * get_value(void * store, int * error);
I'm having hard time coming with any objective reason to prefer one over another, but than again, I don't write C that much. The return-error-code will look more consistent when multiple output parameters are present, however the return-value could be bit easier to use? Not sure.
Is there general consensus on which style is better and why or is just a personal preference?
There tend not to be good, "hard" answers to style-based questions like this. What follows are my opinions; others will disagree.
Having a function simply return its return value usually makes it easier for the caller -- as long as the caller is interested in getting answers, not necessarily in optimal error handling.
Having all functions return success/failure codes -- returning any other data via "result" parameters -- makes for clean and consistent error handling, but tends to be less convenient for callers. You're always having to declare extra variables (of the proper type) to hold return values. You can't necessarily write things like a = f(g());.
Returning ordinary values ordinarily, and indicating errors via an "out of band" ordinary return value, is a popular technique -- the canonical example is the Standard C getchar function -- but it can feel rather ad-hoc and error-prone.
Returning values via the return value, and error codes via a "return" parameter, is unusual. I can see the attraction, but I can't say I've ever used that technique, or would. If there needs to be an error return distinct from the return value, the "C way" (though of course this is generally a pretty bad idea, and now pretty strongly deprecated) is to use some kind of globalish variable, à la errno.
If you want to pay any heed to the original "spirit of C", it was very much for programmer convenience, and was not too worried about rigid consistency, and was generally okay with healthy dollops of inconsistency and ad-hocciness. So using out-of-band error returns is fine.
If you want to pay heed to modern usage, it seems to be increasingly slanted towards conformity and correctness, meaning that consistent error return schemes are a good thing, even if they're less convenient. So having the return value be a success/failure code, and data returned by a result parameter, is fine.
If you want to have the return value be the return value, for convenience, and if errors are unusual, but for those callers who care you want to give them a way of getting fine-grained error information, a good compromise is sometimes to have a separate function to fetch the details of the most-recent error. This can still lead to the same kinds of race conditions as a global variable, but if your library uses some kind of "descriptors" or "handles", such that you can arrange to have this error-details function return the details of the most recent operation on a particular handle, it can work pretty well.
What's the point of throwing exceptions?
For example I stumbled across this:
static List<Integer> list(int [] a) {
if (a == null)
throw new NullPointerException();
//...
But when you don't throw the nullpointer, you'll also get a nullpointer?
I see this regularly and I wanted to know if this is a good habit to learn?
It's better to fail fast. For example the function could do a bunch of stuff before it even references the variable "a" in your example resulting in a lot of unnecessary processing.. It would be best just to fail immediately if you know "a" is null from the very beginning. You could also append a custom error message to the exception as well.
The idea behind the THROW is to prevent the error from stopping your program.
If it's a fatal enough error, your program will stop anyway. But if the program can continue it will, and just let you know that an error occurred.
In many cases, you assign a function to report the error, since you threw it up and know what it is.
I always found throwing exceptions to be a matter of design and readability. For example, generally when I design something I prefer to handle errors where they occur. However an equally valid design would be to throw the exception and handle it somewhere else. I have seen some abstractions where generally your flow is something similar to this...
FlowControl -> GenericMethod(catches exceptions and calls methods only) -> PrivateMethods (generally used to do the work, throws exceptions).
You might find a more complete answer here as well: When to catch the Exception vs When to throw the Exceptions?
It's possible that the rest of your method will not throw the exception and will instead have some kind of undesirable behavior if you use a null pointer. In your example, if it's basically a "ToList" wrapper, it might be implemented as:
static List<Integer> list(int[] a)
{
List<int> ret = new List<int>();
foreach (int i in a)
ret.add(i);
return ret;
}
Instead of throwing, this will simply return an empty list (if I recall correctly at least, I don't think C# throws on null lists used in foreach). As such, you'll need to include an explicit null check and throw to get your desired behavior.
Throwing specific exception means that your application has faced something it shouldn't have. It can be either invalid argument(when someone passes null and current method cannot work with value of null), invalid field state(its value has been changed to some value, which is forbidden for instance current state) and many many more.
Basically when you throw exceptions in a good manner, each person using your e.g. library can preserve its correct flow.
I work in safety critical application development. Recently as a code reviewer I complained against coding style shown below, but couldn't make a strong case against it. So what would be a good argument against such Variable redundancy/duplication, I am looking for cases where this might lead to problems or test cases which might fail, rather than just coding style.
//global data
// global data
int Block1Var;
int Block2Var;
...
//Block1
{
...
Block1Var = someCondition; // someCondition is an logical expression
...
}
//Block2
{
...
Block2Var = Block1Var; // Block2Var is an unconditional copy of Block1Var
...
}
I think a little more context would be helpful perhaps.
You could argue that the value of Block1Var is not guaranteed to stay the
same across concurrent access/modification. This is only valid if Block1Var
ever changes (ie is not only read). I don't know if you are concerned with
multi-threaded applications or not.
Readability is an important issue as well. Future code maintainers
don't want to have to trace around a bunch of trivial assignments.
Depends on what's done with those variables later, but one argument is that it's not future-proof. If, in the future, you change the code such that it changes the value of Block1Var, but Block2Var is used instead (without the additional change) later on, then this will result in erroneous behavior.
If the shown function context reaches a certain length (I'm assuming a lot of detail has been discarded to create the minimal reproducible example for this question), a good next step could be to create a new (sub-)function out of Block 2. This subfunction then should be started assigning Block1Var (-> actual parameter) to Block2Var (-> formal parameter). If there were no other coupling to the rest of the function, one could cut the rest of Block 2 and drop it as a function definition, and would only have to replace the assignment by the subfunction call.
My answer is fairly speculative, but I have seen many cases where this strategy helped me to mark useful points to split a complex function later during the development. Of course, this interpretation only applies to an intermediate stage of development and not to code that is stated to be "ready for release".
An Example
Suppose we have a text to write and could be converted to "uppercase or lowercase", and can be printed "at left, center or right".
Specific case implementation (too many functions)
writeInUpperCaseAndCentered(char *str){//..}
writeInLowerCaseAndCentered(char *str){//..}
writeInUpperCaseAndLeft(char *str){//..}
and so on...
vs
Many Argument function (bad readability and even hard to code without a nice autocompletion IDE)
write( char *str , int toUpper, int centered ){//..}
vs
Context dependent (hard to reuse, hard to code, use of ugly globals, and sometimes even impossible to "detect" a context)
writeComplex (char *str)
{
// analize str and perhaps some global variables and
// (under who knows what rules) put it center/left/right and upper/lowercase
}
And perhaps there are others options..(and are welcome)
The question is:
Is there is any good practice or experience/academic advice for this (recurrent) trilemma ?
EDIT:
What I usually do is to combine "specific case" implementation, with an internal (I mean not in header) general common many-argument function, implementing only used cases, and hiding the ugly code, but I don't know if there is a better way that I don't know. This kind of things make me realize of why OOP was invented.
I'd avoid your first option because as you say the number of function you end up having to implement (though possibly only as macros) can grow out of control. The count doubles when you decide to add italic support, and doubles again for underline.
I'd probably avoid the second option as well. Againg consider what happens when you find it necessary to add support for italics or underlines. Now you need to add another parameter to the function, find all of the cases where you called the function and updated those calls. In short, anoying, though once again you could probably simplify the process with appropriate use of macros.
That leaves the third option. You can actually get some of the benefits of the other alternatives with this using bitflags. For example
#define WRITE_FORMAT_LEFT 1
#define WRITE_FORMAT_RIGHT 2
#define WRITE_FORMAT_CENTER 4
#define WRITE_FORMAT_BOLD 8
#define WRITE_FORMAT_ITALIC 16
....
write(char *string, unsigned int format)
{
if (format & WRITE_FORMAT_LEFT)
{
// write left
}
...
}
EDIT: To answer Greg S.
I think that the biggest improvement is that it means that if I decide, at this point, to add support for underlined text I it takes two steps
Add #define WRITE_FORMAT_UNDERLINE 32 to the header
Add the support for underlines in write().
At this point it can call write(..., ... | WRITE_FORMAT_UNLDERINE) where ever I like. More to the point I don't need to modify pre-existing calls to write, which I would have to do if I added a parameter to its signature.
Another potential benefit is that it allows you do something like the following:
#define WRITE_ALERT_FORMAT (WRITE_FORMAT_CENTER | \
WRITE_FORMAT_BOLD | \
WRITE_FORMAT_ITALIC)
I prefer the argument way.
Because there's going to be some code that all the different scenarios need to use. Making a function out of each scenario will produce code duplication, which is bad.
Instead of using an argument for each different case (toUpper, centered etc..), use a struct. If you need to add more cases then you only need to alter the struct:
typedef struct {
int toUpper;
int centered;
// etc...
} cases;
write( char *str , cases c ){//..}
I'd go for a combination of methods 1 and 2.
Code a method (A) that has all the arguments you need/can think of right now and a "bare" version (B) with no extra arguments. This version can call the first method with the default values. If your language supports it add default arguments. I'd also recommend that you use meaningful names for your arguments and, where possible, enumerations rather than magic numbers or a series of true/false flags. This will make it far easier to read your code and what values are actually being passed without having to look up the method definition.
This gives you a limited set of methods to maintain and 90% of your usages will be the basic method.
If you need to extend the functionality later add a new method with the new arguments and modify (A) to call this. You might want to modify (B) to call this as well, but it's not necessary.
I've run into exactly this situation a number of times -- my preference is none of the above, but instead to use a single formatter object. I can supply it with the number of arguments necessary to specify a particular format.
One major advantage of this is that I can create objects that specify logical formats instead of physical formats. This allows, for example, something like:
Format title = {upper_case, centered, bold};
Format body = {lower_case, left, normal};
write(title, "This is the title");
write(body, "This is some plain text");
Decoupling the logical format from the physical format gives you roughly the same kind of capabilities as a style sheet. If you want to change all your titles from italic to bold-face, change your body style from left justified to fully justified, etc., it becomes relatively easy to do that. With your current code, you're likely to end up searching through all your code and examining "by hand" to figure out whether a particular lower-case, left-justified item is body-text that you want to re-format, or a foot-note that you want to leave alone...
As you already mentioned, one striking point is readability: writeInUpperCaseAndCentered("Foobar!") is much easier to understand than write("Foobar!", true, true), although you could eliminate that problem by using enumerations. On the other hand, having arguments avoids awkward constructions like:
if(foo)
writeInUpperCaseAndCentered("Foobar!");
else if(bar)
writeInLowerCaseAndCentered("Foobar!");
else
...
In my humble opinion, this is a very strong argument (no pun intended) for the argument way.
I suggest more cohesive functions as opposed to superfunctions that can do all kinds of things unless a superfunction is really called for (printf would have been quite awkward if it only printed one type at a time). Signature redundancy should generally not be considered redundant code. Technically speaking it is more code, but you should focus more on eliminating logical redundancies in your code. The result is code that's much easier to maintain with very concise, well-defined behavior. Think of this as the ideal when it seems redundant to write/use multiple functions.