I was recently teaching myself Python and discovered the LBYL/EAFP idioms with regards to error checking before code execution. In Python, it seems the accepted style is EAFP, and it seems to work well with the language.
LBYL (Look Before You Leap):
def safe_divide_1(x, y):
if y == 0:
print "Divide-by-0 attempt detected"
return None
else:
return x/y
EAFP (it's Easier to Ask Forgiveness than Permission):
def safe_divide_2(x, y):
try:
return x/y
except ZeroDivisionError:
print "Divide-by-0 attempt detected"
return None
My question is this: I had never even heard of using EAFP as the primary data validation construct, coming from a Java and C++ background. Is EAFP something that is wise to use in Java? Or is there too much overhead from exceptions? I know that there is only overhead when an exception is actually thrown, so I'm unsure as to why the simpler method of EAFP is not used. Is it just preference?
If you are accessing files, EAFP is more reliable than LBYL, because the operations involved in LBYL are not atomic, and the file system might change between the time you look and the time you leap. Actually, the standard name is TOCTOU - Time of Check, Time of Use; bugs caused by inaccurate checking are TOCTOU bugs.
Consider creating a temporary file that must have a unique name. The best way to find out whether the chosen file name exists yet is to try creating it - making sure you use options to ensure that your operation fails if the file does already exist (in POSIX/Unix terms, the O_EXCL flag to open()
). If you try to test whether the file already exists (probably using access()
), then between the time when that says "No" and the time you try to create the file, someone or something else may have created the file.
Conversely, suppose that you try to read an existing file. Your check that the file exists (LBYL) may say "it is there", but when you actually open it, you find "it is not there".
In both these cases, you have to check the final operation - and the LBYL didn't automatically help.
(If you are messing with SUID or SGID programs, access()
asks a different question; it may be relevant to LBYL, but the code still has to take into account the possibility of failure.)