So I had an intersting discussion with the guys at work about try/catches.
My opinion is slowly becoming: Try/Catches are habits of poor skill in programmers.
Sure, sometimes you need to use them merely to be sure. Or global try/catches *just to be safe*, sure, but relying on them -- I believe it's poor coding.
The argument they brought up was "so, what -- you're supposed to use if's for *everything*?" to which my response (now) is "what? you use try/catches in *everything* method?" -- which I know they don't -- and it bit us.
You see, in a DataGridCellMouseClick or some event simliar to that you can have it attempt to calculate what cell it's in. So, we had something like:
int SomeVal = Convert.ToInt32(DataGridObject.Cells[e.Cell.Row,e.cell.Column].Value.ToString());
Sounds simple, right?
Well, turns out if you click on a column -- it barfs (either row or colum will be < 0 if you click them). So, ok -- to what extent do you do sanity check on data? It's awfully unreasonble to do sanity checking on *everything* *everytime*. So, perhaps you should just do it when you intiate it?
The net result was something close to:
if ( e.Cell.Row < 1 || e.Cell.Row < 1)
/* Assume they clicked on a header column or row */
return;
int SomeVal = Convert.ToInt32(DataGridObject.Cells[e.Cell.Row,e.cell.Column].Value.ToString());
Something I have learned while writing a migration app is that try/catches slow you down an amount that is not insignificant. A couple million times and you are looking at adding minutes or *hours* to your app. So not only have I learned this habit because it made my app much slower, I learned you should pay more attention to your code.
Perhaps slowing down coding to make code cleaner is a better idea. Think it through.
I found a few comments around the net about this too and it seems that some believe try/catches are so infignificant that you should use them freely while others will say that using a try/catch because you don't do proper parsing / variable handling just shows poor coding skills. A very common one is DateTime.Parse versus using DateTime.TryParse -- which I should use Int32.TryParse above (go figure).
On an important note, I do understand (and use myself) try/catches for play-pen type code. Things that *can't* faily, however, I don't allow try/catches. For example, migrations -- they *can not* fail. Ever. Peroid. Hitting a try/catch means *I* fucked up somewhere or someone pulled a network cable (which I need to research how to check for that anyways).
Comments
I've officially come to this
I've officially come to this conclusion:
If you have to use more than a few try/catches in your app then either you suck at your language or your language sucks.
By that I mean if your language doesn't support proper fail-safes that can be implemented in code then your language sucks. If your language does support them but you choose not to use them and take the easy way out -- you suck at your language.
I'm starting to view this much like normal forms in databases. It's good practice. Sure, you can live without it... but to hell with maintenance and cleanliness. If you don't care about that... then don't be surprised when my enthusiasm/give-a-damn is less than optimal especially when the answers are simple such as using TryParse instead of Parse.
Here is a cood example:
try {
File.Open("some_path_that_doesn't exist");
} catch (Exception e) {
MessageBox.Show ("File most likely doesn't exists.");
}
Where is should be:
if ( ! File.exists("Some_path_that_doesn't_exist") {
MessageBox.Show("File doesn't exist");
return;
}
Sure, you could do a FileException handler, but that still involves a try/catch. Since I've learned that try/catches slow you down (albeit not much if you don't use many) it still shows poor coding and usually a lack of understanding of the language.
I'm still trying to decide if I like the ! operator when doing comparisons.
I think it's easier to read if you say if ( something == false ) instead of (! something). If it's easier to read then it's easier to maintain for the dude after you who doesn't know what you were thinking. Make his/her life easier.
I'm still finding this very often:
try { something_else = Convert.ToBoolean(something.ToString()); }
catch { something_else = false; }
When it should be:
something_else = false; /* Not really needed if you do a bail-out in your if statement below */
if ( Boolean.TryParse( something.ToString(), out something_else) == false)
MessageBox.Show("Invalid something.");
Now I do think under certain circumstances try/catches can be used as a time saver.
If, for example, to open a file you have to do 20+ sanity checks (if/else, if/else, etc) then unless you need that verbose of a detailed reason (and you should prefer verbosity, given a choice) then it's acceptable to use a try/catch so long as you later have the intent on going back and applying the verbosity. Users won't know what those stupid exception errors are and if they tell you "it says X" as opposed to "it says lots of stuff.. something about blah blah" then it saves you time in the future.
A good example of using a
A good example of using a try/catch I've found was this:
Someone needed to to delete a list of files.
Cool, you should check to see if they file exists before deleting and all kinds of normal stuff...
problem is security and the weird stuff.
There are many what-if's in this area.
It's not practical to code them all initially because many exceptions exists and coding around them all is very tedious.
I usually do this:
try {
/* TODO - Fix this later */
...
} catch {
MessageBox.Show("dingo");
}
So I can search for "TODO" in all caps and find all those and come back and fix them later.
On a side note, I'm slowly developing a toolkit for these sorts of things.
For a quickie app, it's great usage. For long term -- it's better to actually have most of the actual things that can stop you checked for so you can alert the user specifically why they can't do an action.