Tuesday, September 19, 2006
File.Exists Is Evil
File.Exists. If you code to the CLR you're probably familiar with that. What does it mean?
You call File.Exists and you find out that it exists. What does that mean?
It means that at some point between the time that you called the function and the time it returned that file existed. Or didn't. That's it. That's all you know.
Why is this bad?
It's bad because people tend to take for granted that the result from File.Exists is always *still* true. This is a problem mostly because the function should have been called File.Existed. That's all you really know. It used to be there. No promise about its current availability. Period.
Ok, so let's dig into it deeper. Why is this "evil" and not just "kinda wrong"?
Because devs build assumptions. Developer assumptions often translate into bugs. (Trust me - I'm a tester!) Developers often assume that the result of File.Exists tells them whether or not a file exists. That's not what it does. It only says whether or not in some past time that file existed. Thus, there's an assumption. Thus, a (probable) bug. Ick!
This is a race condition magnet. If you're reading this and you're a tester, then look for File.Exists in your devs' code. It's almost certainly the source of a bug. If you're a developer, ask yourself why you'd ever use File.Exists.
1) Can I do X with the file?
If this is your question, I recommend just trying to do X. Even if File.Exists works most of the time, those other times probably need to deal with whatever exception is thrown. Relying on File.Exists probably puts an implicit race in your code. Just don't go there.
2) Did FOO write something?
If it did, that log may not exist now. Chances are that you want something useful NOW and not a few milliseconds ago. Counting on FOO's file to have existed again introduces a race condition and there's probably an exception you're not wanting to handle. Just catch the exception and skip File.Exists. Make it simple. And robust. Write good code.
3) Should I overwrite or delete BAR?
Um . . . same as the other stuff I just said. Don't. Just don't. Make your code thread-safe. Reliance on File.Exists doesn't do that.
4+) Yes, there are more, but they're similar. I'll skip them.
At best, File.Exists can be a fairly reliable way to know that something *didn't* exist. Even then, there's a race and you're not being threadsafe. At worst, you've opened your code to Heisenbugs that you may not be able to diagnose.
I have no idea why anyone ever introduced such a construct as File.Exists. I can only tell you that it's evil. Avoid it. It only leads to bad code. Let's hope that saner heads prevail in DevDiv and this goes the way of the Democrats^H^H^H^H^H^H^H^H^Hdinosaurs.
Ok, I got a bit glib there. I meant to show examples of crap code that counted (unreliably) on File.Exists. I couldn't do it. It was too painful. Please forgive me.
(P.S. I lean a bit left, politically. Shut up already, lefties! It's a joke.)