I'm new to programming and I have a conceptual question.
That is, can "exception" be perfectly replaced by "if.. else" ?
I know "exception" is to handling some exceptional conditions that might cause error or crash.
But we also use "if.. else" to ensure the correctness of value of variables, don't we?
Or "exception" can really be replaced by "if.. else", but using "exception" has other benefits(like convenience?)
Thank you, and sorry for my poor English.
The biggest difference between exceptions and "if..else" is that exceptions pass up the call stack: an exception raised in one function can be caught in a caller any number of frames up the stack. Using "if" statements doesn't let you transfer control in this way, everything has to be handled in the same function that detected the condition.
Most of your questions relate to Python, so here is an answer based on that fact.
In Python, it is idiomatic (or "pythonic") to use try-except blocks. We call this "EAFP": Easier to ask for forgiveness than permission.
In C, where there were no exceptions, it was usual to "LBYL": Look before you leap, resulting in lots of if (...) statements.
So, while you can LBYL, you should follow the idioms of the language in which you are programming: using exceptions for handling exceptional cases and if-statements for conditionals.
Technically, the answer is yes, exceptions can be perfectly replaced by if-else. Many languages, C for example, have no native notion of exceptions that can be thrown and caught.
The primary advantage of exceptions is code readability and maintainability. They serve a different purpose than if-else. Exceptions are for exceptional conditions, while if-else is for program flow.
See this excellent article explaining the difference.
That's a lot of branch conditions to manage. In theory, exceptions aren't necessary for perfect code, but perfect code does not exist in real life. Exceptions are a well-established mechanism for dealing with problems in a controlled manner.
The old way for handling an error from a function looks something like this:
int result = function_returns_error_code();
if (result != GOOD)
{
/* handle problem */
}
else
{
/* keep going */
}
The problem with this solution (and others like it - using if-else) is that if there is a real problem, and the programmer does not properly handle it with an if...else (if the function returns an error code indicating major problems, but the programmer forgets about it), it is left ignored. With an exception, it goes further and further up the call stack ) until it is either handled or the program quits.
Further, it is tedious to check for error codes in functions, or pass a parameter into which to put an error code. It is simpler, cleaner, and better to use exceptions, for maintainability and abstraction.
In most high-level languages working with exceptions is often more efficient than if-else because you avoid multiple validation. eg:
if value is not 0 then print 10 / value
In most interpreters 10 / value will internally test whether value is a valid divider before using it so you've actually tested for the same problem twice. In some cases the exception may come all the way up from hardware so no software validation is happening at all.
On the other hand:
try print 10 / value ... catch exception
Will only test whether value is valid once. Furthermore there's a good chance the test will be better optimised than your own code and more capable of handling truly unexpected conditions (like out of memory errors).
Related
I am trying to implement a utility library in nodeJS that I can use in different projects. I am stuck with how to handle errors properly.For example suppose I have a function
function dateCompare(date1,operator,date2) // it can take either a date object or valid date string.
Now suppose an invalid input is supplied-
1. I can return error in result like asynchronous logic- {error:true,result:""}, but this prevents me from using my function as if((date1,'eq',date2) || (date3,'l3',date4)
2. If I throw custom exception here, then I am afraid that node is single threaded and creating error context is very expensive.
How can we handle it so that it is easy to use as well as not very expensive? Under what circumstances throwing exceptions will be more appropriate even if it is too expensive ? some practical use cases will be very helpful.
There's no "right" answer for questions like this. There are various different philosophies and you have to decide which one makes the most sense for you or for your context.
Here's my general scheme:
If you detect a serious programming mistake such as a required argument to a function is missing or is the wrong type, then I prefer to just throw an exception and spell out in the exception msg exactly what is wrong. This should get seen by the developer the first time this code is run and they should then know they need to correct their code immediately. The general idea here is that you want the developer to see their error immediately and throwing an exception is usually the fastest way to do so and you can put a useful message in the exception.
If there are expected error return values such as "user name already taken" or "user name contains invalid characters" that are not programming mistakes, but are just an indication of why a given operation (perhaps containing user data) did not complete, then I would craft return values from the function that communicate this info to the caller.
If your function needs to return either a result or an error, then you have to decide on a case by case basis if it is easy to come up with a range of error values that are easily detectable as separate from the successful return values. For example, Array.prototype.indexOf() returns a negative value to indicate the value was not found or zero or a positive number to indicate it is returning an index. These ranges are completely independent so they are easy to code a test to distinguish them.
Another reason to throw an exception is that your code is likely to be used in a circumstance where it's simpler to let the exception propagate up several calling levels or block levels rather than manually writing code to propagate errors. This is a double edged sword. While sometimes it's very useful to let the exception propagate, sometimes you actually need to know about and deal with the exception at each level anyway to properly clean up in an error condition (release resources, etc...) so you can't let it go up that may levels automatically anyway.
If such a distinction is not simple to do for either you the code of the function or the developer who will call it, then sometimes it makes sense to return an object that has more than one property, one of which is an error property, another of which is a value.
In your specific case of:
function dateCompare(date1,operator,date2)
and
if (dateCompare(date1,'eq',date2) || dateCompare(date3,'l3',date4))
It sure would be convenient if the function just returns a boolean and throws an exception of the date values or operator are invalid. Whether this is good design decision depends a bit on how this is going to be used. If you're in a tight loop, running this on lots of values, many of which will be badly formatted and would throw such an exception and performance is important in this case, then it may be better to return the above-described object and change how you write the calling code.
But, if a format failure is not a regular expected case or you're only doing it once or the performance difference of an exception vs. a return value wouldn't even be noticed (which is usually the case), then throw the exception - it's a clean way to handle invalid input without polluting the expected use case of the function.
How can we handle it so that it is easy to use as well as not very
expensive?
It's not expensive to throw an exception upon bad input if that isn't the normally expected case. Plus, unless this code is in some kind of tight loop and called many times, it's unlikely you would even notice the difference between a return value and a thrown/caught exception. So, I'd suggest you code to make the expected cases simpler to code for and use exceptions for the unexpected conditions. Then, your expected code path doesn't go the exception route. In other words, exceptions actually are "exceptions" to normal.
Under what circumstances throwing exceptions will be more appropriate
even if it is too expensive?
See the description above.
I'm working on a simple programming language for kids, based on Karel. For controlling program flow, I currently provide these facilities (in pseudocode):
defining parameterless procedures
if [not] EXPRESSION STATEMENT
while [not] EXPRESSION STATEMENT
I don't have any means to return from a procedure, and I don't provide the else statement.
Take the following code for an example:
if something
statement1
if not something
statement2
The execution of code flows to if, executing statement1 if something is true;
then testing if something is not true (but the state of the program has changed!), then executing statement2. This can lead to both tests succeeding.
Does this limit the programmer? So far I've been able to solve all of my example problems by just using if ... if not ..., or using if not first, then if.
So, my question is:
Is adding the else statement necessary? It would make the language a bit more complicated with having more keywords. Are all problems that would be solvable with else statement solvable also without it, albeit more complicated?
Or is omitting the else statement actually making the language more complicated and counter-intuitive?
If something is expensive to evaluate then your language with else might give a problem because the evaluation will be performed twice.
Another potential problem is that if statement1 can modify the value of something you may end up with both tests succeeding - something that could not happen if you used else.
Of course these problems can be mitigated by storing the result in a temporary local variable:
bool result = something
if result
statement1
if not result
statement2
So no you aren't limiting the programmer in what is possible - everything that can be done with else can be done without it by using the above approach. But it is a little more code to write each time and it introduces a few new potential problems for the unwary programmer that would be avoided if you allowed else.
Semantically speaking you could avoid having the else construct, but from practical point of view I don't see any necessity of doing that.
The concept of do something if something is true, otherwise something else is not so strange and confusing, it sounds actually quite straightforward that having to evaluate and negate an expression again just to check its negation.. it's a free (in sense of "with no added complexity") optional synctactic sugar that is automatic when developing a language.
I saw many other features really more useless compared to the else statement.. then you are not considering the fact that evaluating a condition twice maybe harmful for side-effects or for complexity (wasted cpu?) or for the fact itself that you already have calculated it and you have to do it again for a lack of the language not because it's senseful.
If something has side-effects than your approach will cause them to happen twice, which is probably not what you want.
IMHO It's bad idea to teach children to duplicate code.
So, I was just coding a bit today, and I realized that I don't have much consistency when it comes to a coding style when programming functions. One of my main concerns is whether or not its proper to code it so that you check that the input of the user is valid OUTSIDE of the function, or just throw the values passed by the user into the function and check if the values are valid in there. Let me sketch an example:
I have a function that lists hosts based on an environment, and I want to be able to split the environment into chunks of hosts. So an example of the usage is this:
listhosts -e testenv -s 2 1
This will get all the hosts from the "testenv", split it up into two parts, and it is displaying part one.
In my code, I have a function that you pass it in a list, and it returns a list of lists based on you parameters for splitting. BUT, before I pass it a list, I first verify the parameters in my MAIN during the getops process, so in the main I check to make sure there are no negatives passed by the user, I make sure the user didnt request to split into say, 4 parts, but asking to display part 5 (which would not be valid), etc.
tl;dr: Would you check the validity of a users input the flow of you're MAIN class, or would you do a check in your function itself, and either return a valid response in the case of valid input, or return NULL in the case of invalid input?
Obviously both methods work, I'm just interested to hear from experts as to which approach is better :) Thanks for any comments and suggestions you guys have! FYI, my example is coded in Python, but I'm still more interested in a general programming answer as opposed to a language-specific one!
Good question! My main advice is that you approach the problem systematically. If you are designing a function f, here is how I think about its specification:
What are the absolute requirements that a caller of f must meet? Those requirements are f's precondition.
What does f do for its caller? When f returns, what is the return value and what is the state of the machine? Under what circumstances does f throw an exception, and what exception is thrown? The answers to all these questions constitute f's postcondition.
The precondition and postcondition together constitute f's contract with callers.
Only a caller meeting the precondition gets to rely on the postcondition.
Finally, bearing directly on your question, what happens if f's caller doesn't meet the precondition? You have two choices:
You guarantee to halt the program, one hopes with an informative message. This is a checked run-time error.
Anything goes. Maybe there's a segfault, maybe memory is corrupted, maybe f silently returns a wrong answer. This is an unchecked run-time error.
Notice some items not on this list: raising an exception or returning an error code. If these behaviors are to be relied upon, they become part of f's contract.
Now I can rephrase your question:
What should a function do when its caller violates its contract?
In most kinds of applications, the function should halt the program with a checked run-time error. If the program is part of an application that needs to be reliable, either the application should provide an external mechanism for restarting an application that halts with a checked run-time error (common in Erlang code), or if restarting is difficult, all functions' contracts should be made very permissive so that "bad input" still meets the contract but promises always to raise an exception.
In every program, unchecked run-time errors should be rare. An unchecked run-time error is typically justified only on performance grounds, and even then only when code is performance-critical. Another source of unchecked run-time errors is programming in unsafe languages; for example, in C, there's no way to check whether memory pointed to has actually been initialized.
Another aspect of your question is
What kinds of contracts make the best designs?
The answer to this question varies more depending on the problem domain.
Because none of the work I do has to be high-availability or safety-critical, I use restrictive contracts and lots of checked run-time errors (typically assertion failures). When you are designing the interfaces and contracts of a big system, it is much easier if you keep the contracts simple, you keep the preconditions restrictive (tight), and you rely on checked run-time errors when arguments are "bad".
I have a function that you pass it in a list, and it returns a list of lists based on you parameters for splitting. BUT, before I pass it a list, I first verify the parameters in my MAIN during the getops process, so in the main I check to make sure there are no negatives passed by the user, I make sure the user didnt request to split into say, 4 parts, but asking to display part 5.
I think this is exactly the right way to solve this particular problem:
Your contract with the user is that the user can say anything, and if the user utters a nonsensical request, your program won't fall over— it will issue a sensible error message and then continue.
Your internal contract with your request-processing function is that you will pass it only sensible requests.
You therefore have a third function, outside the second, whose job it is to distinguish sense from nonsense and act accordingly—your request-processing function gets "sense", the user is told about "nonsense", and all contracts are met.
One of my main concerns is whether or not its proper to code it so that you check that the input of the user is valid OUTSIDE of the function.
Yes. Almost always this is the best design. In fact, there's probably a design pattern somewhere with a fancy name. But if not, experienced programmers have seen this over and over again. One of two things happens:
parse / validate / reject with error message
parse / validate / process
This kind of design has one data type (request) and four functions. Since I'm writing tons of Haskell code this week, I'll give an example in Haskell:
data Request -- type of a request
parse :: UserInput -> Request -- has a somewhat permissive precondition
validate :: Request -> Maybe ErrorMessage -- has a very permissive precondition
process :: Request -> Result -- has a very restrictive precondition
Of course there are many other ways to do it. Failures could be detected at the parsing stage as well as the validation stage. "Valid request" could actually be represented by a different type than "unvalidated request". And so on.
I'd do the check inside the function itself to make sure that the parameters I was expecting were indeed what I got.
Call it "defensive programming" or "programming by contract" or "assert checking parameters" or "encapsulation", but the idea is that the function should be responsible for checking its own pre- and post-conditions and making sure that no invariants are violated.
If you do it outside the function, you leave yourself open to the possibility that a client won't perform the checks. A method should not rely on others knowing how to use it properly.
If the contract fails you either throw an exception, if your language supports them, or return an error code of some kind.
Checking within the function adds complexity, so my personal policy is to do sanity checking as far up the stack as possible, and catch exceptions as they arise. I also make sure that my functions are documented so that other programmers know what the function expects of them. They may not always follow such expectations, but to be blunt, it is not my job to make their programs work.
It often makes sense to check the input in both places.
In the function you should validate the inputs and throw an exception if they are incorrect. This prevents invalid inputs causing the function to get halfway through and then throw an unexpected exception like "array index out of bounds" or similar. This will make debugging errors much simpler.
However throwing exceptions shouldn't be used as flow control and you wouldn't want to throw the raw exception straight to the user, so I would also add logic in the user interface to make sure I never call the function with invalid inputs. In your case this would be displaying a message on the console, but in other cases it might be showing a validation error in a GUI, possibly as you are typing.
"Code Complete" suggests an isolation strategy where one could draw a line between classes that validate all input and classes that treat their input as already validated. Anything allowed to pass the validation line is considered safe and can be passed to functions that don't do validation (they use asserts instead, so that errors in the external validation code can manifest themselves).
How to handle errors depends on the programming language; however, when writing a commandline application, the commandline really should validate that the input is reasonable. If the input is not reasonable, the appropriate behavior is to print a "Usage" message with an explanation of the requirements as well as to exit with a non-zero status code so that other programs know it failed (by testing the exit code).
Silent failure is the worst kind of failure, and that is what happens if you simply return incorrect results when given invalid arguments. If the failure is ever caught, then it will most likely be discovered very far away from the true point of failure (passing the invalid argument). Therefore, it is best, IMHO to throw an exception (or, where not possible, to return an error status code) when an argument is invalid, since it flags the error as soon as it occurs, making it much easier to identify and correct the true cause of failure.
I should also add that it is very important to be consistent in how you handle invalid inputs; you should either check and throw an exception on invalid input for all functions or do that for none of them, since if users of your interface discover that some functions throw on invalid input, they will begin to rely on this behavior and will be incredibly surprised when other function simply return invalid results rather than complaining.
As part of a code standards document I wrote awhile back, I enforce "you must always use braces for loops and/or conditional code blocks, even (especially) if they're only one line."
Example:
// this is wrong
if (foo)
//bar
else
//baz
while (stuff)
//things
// This is right.
if (foo) {
// bar
} else {
// baz
}
while (things) {
// stuff
}
When you don't brace a single-line, and then someone comments it out, you're in trouble. If you don't brace a single-line, and the indentation doesn't display the same on someone else's machine... you're in trouble.
So, question: are there good reasons why this would be a mistaken or otherwise unreasonable standard? There's been some discussion on it, but no one can offer me a better counterargument than "it feels ugly".
The best counter argument I can offer is that the extra line(s) taken up by the space reduce the amount of code you can see at one time, and the amount of code you can see at one time is a big factor in how easy it is to spot errors. I agree with the reasons you've given for including braces, but in many years of C++ I can only think of one occasion when I made a mistake as a result and it was in a place where I had no good reason for skipping the braces anyway. Unfortunately I couldn't tell you if seeing those extra lines of code ever helped in practice or not.
I'm perhaps more biased because I like the symmetry of matching braces at the same indentation level (and the implied grouping of the contained statements as one block of execution) - which means that adding braces all the time adds a lot of lines to the project.
I enforce this to a point, with minor exceptions for if statements which evaluate to either return or to continue a loop.
So, this is correct by my standard:
if(true) continue;
As is this
if(true) return;
But the rule is that it is either a return or continue, and it is all on the same line. Otherwise, braces for everything.
The reasoning is both for the sake of having a standard way of doing it, and to avoid the commenting problem you mentioned.
I see this rule as overkill. Draconian standards don't make good programmers, they just decrease the odds that a slob is going to make a mess.
The examples you give are valid, but they have better solutions than forcing braces:
When you don't brace a single-line, and then someone comments it out, you're in trouble.
Two practices solve this better, pick one:
1) Comment out the if, while, etc. before the one-liner with the one-liner. I.e. treat
if(foo)
bar();
like any other multi-line statement (e.g. an assignment with multiple lines, or a multiple-line function call):
//if(foo)
// bar();
2) Prefix the // with a ;:
if(foo)
;// bar();
If you don't brace a single-line, and the indentation doesn't display the same on someone else's machine... you're in trouble.
No, you're not; the code works the same but it's harder to read. Fix your indentation. Pick tabs or spaces and stick with them. Do not mix tabs and spaces for indentation. Many text editors will automatically fix this for you.
Write some Python code. That will fix at least some bad indentation habits.
Also, structures like } else { look like a nethack version of a TIE fighter to me.
are there good reasons why this would be a mistaken or otherwise unreasonable standard? There's been some discussion on it, but no one can offer me a better counterargument than "it feels ugly".
Redundant braces (and parentheses) are visual clutter. Visual clutter makes code harder to read. The harder code is to read, the easier it is to hide bugs.
int x = 0;
while(x < 10);
{
printf("Count: %d\n", ++x);
}
Forcing braces doesn't help find the bug in the above code.
P.S. I'm a subscriber to the "every rule should say why" school, or as the Dalai Lama put it, "Know the rules so that you may properly break them."
I have yet to have anyone come up with a good reason not to always use curly braces.
The benefits far exceed any "it feels ugly" reason I've heard.
Coding standard exist to make code easier to read and reduce errors.
This is one standard that truly pays off.
I find it hard to argue with coding standards that reduce errors and make the code more readable. It may feel ugly to some people at first, but I think it's a perfectly valid rule to implement.
I stand on the ground that braces should match according to indentation.
// This is right.
if (foo)
{
// bar
}
else
{
// baz
}
while (things)
{
// stuff
}
As far as your two examples, I'd consider yours slightly less readable since finding the matching closing parentheses can be hard, but more readable in cases where indentation is incorrect, while allowing logic to be inserted easier. It's not a huge difference.
Even if indentation is incorrect, the if statement will execute the next command, regardless of whether it's on the next line or not. The only reason for not putting both commands on the same line is for debugger support.
The one big advantage I see is that it's easier to add more statements to conditionals and loops that are braced, and it doesn't take many additional keystrokes to create the braces at the start.
My personal rule is if it's a very short 'if', then put it all on one line:
if(!something) doSomethingElse();
Generally I use this only when there are a bunch of ifs like this in succession.
if(something == a) doSomething(a);
if(something == b) doSomething(b);
if(something == b) doSomething(c);
That situation doesn't arise very often though, so otherwise, I always use braces.
At present, I work with a team that lives by this standard, and, while I'm resistant to it, I comply for uniformity's sake.
I object for the same reason I object to teams that forbid use of exceptions or templates or macros: If you choose to use a language, use the whole language. If the braces are optional in C and C++ and Java, mandating them by convention shows some fear of the language itself.
I understand the hazards described in other answers here, and I understand the yearning for uniformity, but I'm not sympathetic to language subsetting barring some strict technical reason, such as the only compiler for some environment not accommodating templates, or interaction with C code precluding broad use of exceptions.
Much of my day consists of reviewing changes submitted by junior programmers, and the common problems that arise have nothing to do with brace placement or statements winding up in the wrong place. The hazard is overstated. I'd rather spend my time focusing on more material problems than looking for violations of what the compiler would happily accept.
The only way coding standards can be followed well by a group of programmers is to keep the number of rules to a minimum.
Balance the benefit against the cost (every extra rule confounds and confuses programmers, and after a certain threshold, actually reduces the chance that programmers will follow any of the rules)
So, to make a coding standard:
Make sure you can justify every rule with clear evidence that it is better than the alternatives.
Look at alternatives to the rule - is it really needed? If all your programmers use whitespace (blank lines and indentation) well, an if statement is very easy to read, and there is no way that even a novice programmer can mistake a statement inside an "if" for a statement that is standalone. If you are getting lots of bugs relating to if-scoping, the root cause is probably that you have a poor whitepsace/indentation style that makes code unnecessarily difficult to read.
Prioritise your rules by their measurable effect on code quality. How many bugs can you avoid by enforcing a rule (e.g. "always check for null", "always validate parameters with an assert", "always write a unit test" versus "always add some braces even if they aren't needed"). The former rules will save you thousands of bugs a year. The brace rule might save you one. Maybe.
Keep the most effective rules, and discard the chaff. Chaff is, at a minimum, any rule that will cost you more to implement than any bugs that might occur by ignoring the rule. But probably if you have more than about 30 key rules, your programmers will ignore many of them, and your good intentions will be as dust.
Fire any programmer who comments out random bits of code without reading it :-)
P.S. My stance on bracing is: If the "if" statement or the contents of it are both a single line, then you may omit the braces. That means that if you have an if containing a one-line comment and a single line of code, the contents take two lines, and therefore braces are required. If the if condition spans two lines (even if the contents are a single line), then you need braces. This means you only omit braces in trivial, simple, easily read cases where mistakes are never made in practice. (When a statement is empty, I don't use braces, but I always put a comment clearly stating that it is empty, and intentionally so. But that's bordering on a different topic: being explicit in code so that readers know that you meant a scope to be empty rather than the phone rang and you forgot to finish the code)
Many languanges have a syntax for one liners like this (I'm thinking of perl in particular) to deal with such "ugliness". So something like:
if (foo)
//bar
else
//baz
can be written as a ternary using the ternary operator:
foo ? bar : baz
and
while (something is true)
{
blah
}
can be written as:
blah while(something is true)
However in languages that don't have this "sugar" I would definitely include the braces. Like you said it prevents needless bugs from creeping in and makes the intention of the programmer clearer.
I am not saying it is unreasonable, but in 15+ years of coding with C-like languages, I have not had a single problem with omitting the braces. Commenting out a branch sounds like a real problem in theory - I've just never seen it happening in practice.
Another advantage of always using braces is that it makes search-and-replace and similar automated operations easier.
For example: Suppose I notice that functionB is usually called immediately after functionA, with a similar pattern of arguments, and so I want to refactor that duplicated code into a new combined_function. A regex could easily handle this refactoring if you don't have a powerful enough refactoring tool (^\s+functionA.*?;\n\s+functionB.*?;) but, without braces, a simple regex approach could fail:
if (x)
functionA(x);
else
functionA(y);
functionB();
would become
if (x)
functionA(x);
else
combined_function(y);
More complicated regexes would work in this particular case, but I've found it very handy to be able to use regex-based search-and-replace, one-off Perl scripts, and similar automated code maintenance, so I prefer a coding style that doesn't make that needlessly complicated.
I don't buy into your argument. Personally, I don't know anyone who's ever "accidentally" added a second line under an if. I would understand saying that nested if statements should have braces to avoid a dangling else, but as I see it you're enforcing a style due to a fear that, IMO, is misplaced.
Here are the unwritten (until now I suppose) rules I go by. I believe it provides readability without sacrificing correctness. It's based on a belief that the short form is in quite a few cases more readable than the long form.
Always use braces if any block of the if/else if/else statement has more than one line. Comments count, which means a comment anywhere in the conditional means all sections of the conditional get braces.
Optionally use braces when all blocks of the statement are exactly one line.
Never place the conditional statement on the same line as the condition. The line after the if statement is always conditionally executed.
If the conditional statement itself performs the necessary action, the form will be:
for (init; term; totalCount++)
{
// Intentionally left blank
}
No need to standardize this in a verbose manner, when you can just say the following:
Never leave braces out at the expense of readability. When in doubt, choose to use braces.
I think the important thing about braces is that they very definitely express the intent of the programmer. You should not have to infer intent from indentation.
That said, I like the single-line returns and continues suggested by Gus. The intent is obvious, and it is cleaner and easier to read.
If you have the time to read through all of this, then you have the time to add extra braces.
I prefer adding braces to single-line conditionals for maintainability, but I can see how doing it without braces looks cleaner. It doesn't bother me, but some people could be turned off by the extra visual noise.
I can't offer a better counterargument either. Sorry! ;)
For things like this, I would recommend just coming up with a configuration template for your IDE's autoformatter. Then, whenever your users hit alt-shift-F (or whatever the keystroke is in your IDE of choice), the braces will be automatically added. Then just say to everyone: "go ahead and change your font coloring, PMD settings or whatever. Please don't change the indenting or auto-brace rules, though."
This takes advantage of the tools available to us to avoid arguing about something that really isn't worth the oxygen that's normally spent on it.
Depending on the language, having braces for a single lined conditional statement or loop statement is not mandatory. In fact, I would remove them to have fewer lines of code.
C++:
Version 1:
class InvalidOperation{};
//...
Divide(10, 0);
//...
Divide(int a, in b)
{
if(b == 0 ) throw InvalidOperation();
return a/b;
}
Version 2:
class InvalidOperation{};
//...
Divide(10, 0);
//...
Divide(int a, in b)
{
if(b == 0 )
{
throw InvalidOperation();
}
return a/b;
}
C#:
Version 1:
foreach(string s in myList)
Console.WriteLine(s);
Version2:
foreach(string s in myList)
{
Console.WriteLine(s);
}
Depending on your perspective, version 1 or version 2 will be more readable. The answer is rather subjective.
Wow. NO ONE is aware of the dangling else problem? This is essentially THE reason for always using braces.
In a nutshell, you can have nasty ambiguous logic with else statements, especially when they're nested. Different compilers resolve the ambiguity in their own ways. It can be a huge problem to leave off braces if you don't know what you're doing.
Aesthetics and readability has nothing to do it.
This question already has answers here:
Advantage of switch over if-else statement
(23 answers)
Eliminating `switch` statements [closed]
(23 answers)
Is there any significant difference between using if/else and switch-case in C#?
(21 answers)
Closed 2 years ago.
Why you would want to use a switch block over a series of if statements?
switch statements seem to do the same thing but take longer to type.
As with most things you should pick which to use based on the context and what is conceptually the correct way to go. A switch is really saying "pick one of these based on this variables value" but an if statement is just a series of boolean checks.
As an example, if you were doing:
int value = // some value
if (value == 1) {
doThis();
} else if (value == 2) {
doThat();
} else {
doTheOther();
}
This would be much better represented as a switch as it then makes it immediately obviously that the choice of action is occurring based on the value of "value" and not some arbitrary test.
Also, if you find yourself writing switches and if-elses and using an OO language you should be considering getting rid of them and using polymorphism to achieve the same result if possible.
Finally, regarding switch taking longer to type, I can't remember who said it but I did once read someone ask "is your typing speed really the thing that affects how quickly you code?" (paraphrased)
If you are switching on the value of a single variable then I'd use a switch every time, it's what the construct was made for.
Otherwise, stick with multiple if-else statements.
concerning Readability:
I typically prefer if/else constructs over switch statements, especially in languages that allows fall-through cases. What I've found, often, is as the projects age, and multiple developers gets involved, you'll start having trouble with the construction of a switch statement.
If they (the statements) become anything more than simple, many programmers become lazy and instead of reading the entire statement to understand it, they'll simply pop in a case to cover whatever case they're adding into the statement.
I've seen many cases where code repeats in a switch statement because a person's test was already covered, a simple fall-though case would have sufficed, but laziness forced them to add the redundant code at the end instead of trying to understand the switch. I've also seen some nightmarish switch statements with many cases that were poorly constructed, and simply trying to follow all the logic, with many fall-through cases dispersed throughout, and many cases which weren't, becomes difficult ... which kind of leads to the first/redundancy problem I talked about.
Theoretically, the same problem could exist with if/else constructs, but in practice this just doesn't seem to happen as often. Maybe (just a guess) programmers are forced to read a bit more carefully because you need to understand the, often, more complex conditions being tested within the if/else construct? If you're writing something simple that you know others are likely to never touch, and you can construct it well, then I guess it's a toss-up. In that case, whatever is more readable and feels best to you is probably the right answer because you're likely to be sustaining that code.
concerning Speed:
Switch statements often perform faster than if-else constructs (but not always). Since the possible values of a switch statement are laid out beforehand, compilers are able to optimize performance by constructing jump tables. Each condition doesn't have to be tested as in an if/else construct (well, until you find the right one, anyway).
However this isn't always the case, though. If you have a simple switch, say, with possible values of 1 to 10, this will be the case. The more values you add requires the jump tables to be larger and the switch becomes less efficient (not than an if/else, but less efficient than the comparatively simple switch statement). Also, if the values are highly variant ( i.e. instead of 1 to 10, you have 10 possible values of, say, 1, 1000, 10000, 100000, and so on to 100000000000), the switch is less efficient than in the simpler case.
Hope this helps.
Switch statements are far easier to read and maintain, hands down. And are usually faster and less error prone.
Use switch every time you have more than 2 conditions on a single variable, take weekdays for example, if you have a different action for every weekday you should use a switch.
Other situations (multiple variables or complex if clauses you should Ifs, but there isn't a rule on where to use each.
I personally prefer to see switch statements over too many nested if-elses because they can be much easier to read. Switches are also better in readability terms for showing a state.
See also the comment in this post regarding pacman ifs.
This depends very much on the specific case. Preferably, I think one should use the switch over the if-else if there are many nested if-elses.
The question is how much is many?
Yesterday I was asking myself the same question:
public enum ProgramType {
NEW, OLD
}
if (progType == OLD) {
// ...
} else if (progType == NEW) {
// ...
}
if (progType == OLD) {
// ...
} else {
// ...
}
switch (progType) {
case OLD:
// ...
break;
case NEW:
// ...
break;
default:
break;
}
In this case, the 1st if has an unnecessary second test. The 2nd feels a little bad because it hides the NEW.
I ended up choosing the switch because it just reads better.
I have often thought that using elseif and dropping through case instances (where the language permits) are code odours, if not smells.
For myself, I have normally found that nested (if/then/else)s usually reflect things better than elseifs, and that for mutually exclusive cases (often where one combination of attributes takes precedence over another), case or something similar is clearer to read two years later.
I think the select statement used by Rexx is a particularly good example of how to do "Case" well (no drop-throughs) (silly example):
Select
When (Vehicle ¬= "Car") Then
Name = "Red Bus"
When (Colour == "Red") Then
Name = "Ferrari"
Otherwise
Name = "Plain old other car"
End
Oh, and if the optimisation isn't up to it, get a new compiler or language...
The tendency to avoid stuff because it takes longer to type is a bad thing, try to root it out. That said, overly verbose things are also difficult to read, so small and simple is important, but it's readability not writability that's important. Concise one-liners can often be more difficult to read than a simple well laid out 3 or 4 lines.
Use whichever construct best descibes the logic of the operation.
Let's say you have decided to use switch as you are only working on a single variable which can have different values. If this would result in a small switch statement (2-3 cases), I'd say that is fine. If it seems you will end up with more I would recommend using polymorphism instead. An AbstractFactory pattern could be used here to create an object that would perform whatever action you were trying to do in the switches. The ugly switch statement will be abstracted away and you end up with cleaner code.