EAFP vs LBYL (was Re: A little disappointed so far)

Alex Martelli aleax at aleax.it
Mon May 19 15:26:50 EDT 2003


Robin Becker wrote:
   ...
> If race conditions are a problem shouldn't we be doing something like
> 
> while not havelockon(thefile):
>         pass    # or sleep etc
> useappropriately(thefile)
> giveuplockon(thefile)
> 
> if we actually need to do something with/to thefile?

I don't know, should we?  Will that lock lock all of the directories
upwards from the file, all the way up to root, so that no permission
change can occur that may invalidate whatever tests you're performing
in the LBYL version -- just for example?  I've never seen any lock
mechanism or convention that was as powerful as that -- and yet it
would seem to be a very fundamental operation.

On the other hand, simply trying to open the file for reading will
either succeed or fail and (at least in the implementations I'm
familiar with) if it succeeds it leaves you with a handle suitable
for reading no matter what changes occur later on directories &c.


> The real problem, for me at least, seems to be that concurrency is hard
> no matter how you attempt to deal with it. I guess that race conditions
> could apply to almost every file operation nowadays, but few people
> program that way. Trying to deal with the race using try/except seems
> harder than using an appropriate guard clause or busy loop.

And what would the "appropriate guard clause or busy loop" be to
protect against changes to directory permissions?  And why would
that be easier than trying to open in the try clause of a try/except?

Concurrency is hard, but separating the guards from the operation they
guard can only make things harder than attempting a single "do this"
operation, which will either fail, or atomically succeed-and-perform.
Locking may be a last resort in some cases but shouldn't prevent us
from choosing the best underlying structure.

Consider locking itself.  You're apparently imagining that 'thefile'
itself carries a locking indication or indexes into some global
structure which carries the lock indication for it.  But what should
the primitives be?  "Check if this file is free for locking" and
"acquire lock blindly assuming that the file is free for locking"???
Sheer madness.  Clearly we want an ATOMIC operation that attempts to
perform the locking and either FAILS or SUCCEEDS _and_ in that case 
also performs the operation.  In other words, we want a primitive that
is suitable for EAFP, *NOT* one designed for LBYL -- once again, LBYL
is simply an inferior architecture, period.  (Whether the indication
of failure is returned in-band, e.g. as a boolean or error-return-code,
or out-of-band by raising an exception, is a separate issue here -- in
general if you want to choose ONE good solution to be generalized OOB
is it, because it also applies well to primitives that have to return a
result, e.g. a handle, in case of success, AND avoids any "oops forgot
to check for errors" issues with errors being silently ignored).


I'm leaving for an extended trip in a few hours and so won't be able
to pursue this debate further.  However, this should be no big loss,
because people who *STILL* just can't see it are apparently beyond 
any hope of helping through debate, anyway;-).


Alex





More information about the Python-list mailing list