October 23rd 2005 #
random, October 23rd 2005
SBCL's Package Locking Interface To Change?
Even though SBCL has never been an implementation to worry overly about breaking backwards compatibility, I would like to hear from people potentially affected by this: if you handle conditions of type PACKAGE-LOCK-VIOLATION in your code, please do read the following, and feel free to chime in on sbcl-devel.
Consider the following:
(flet ((cons ())) (cons))
Currently, as documented in the fine manual, SBCL signals a continuable compile-time PACKAGE-LOCK-VIOLATION, which, if unhandled, is converted into code that causes a runtime PROGRAM-ERROR.
To be exact, the compile-time signal is via SIGNAL, meaning that unless you have a handler around the compilation you're never going to see it, just the PROGRAM-ERROR it gets converted to.
The problem with this is that it is generally a bad idea to use SIGNAL with subtypes of SERIOUS-CONDITION, which are according to ANSI "serious enough to require interactive intervention if not handled". Furthermore: "such a condition is usually signaled with ERROR rather then SIGNAL".
The situation is made worse by the fact that our PACKAGE-LOCK-VIOLATION is a subtype of ERROR, meaning that an apparently innocent looking handler, such as the following, will change the behaviour of the compiler:
(handler-case (compile-file ...) (error (e) (format t "Failed: ~A" e)))
If the file to be compiled causes a compile-time package lock violation — even if the code was actually in a dead branch — we will catch the error and claim failure. Without the handler we silently convert the code in question to signal a runtime PROGRAM-ERROR.
Why do we document the signaling behaviour so exactly? The intention is to allow users to set up handlers around eg. compilations of third-party packages that violate package locks, selectively bypassing some of these violations via the CONTINUE restart.
Something's gotto give. Either we: (1) Punt on the compile-time behaviour and just convert to the PROGRAM-ERROR right away. (2) Reorganize our condition hiearchy, and first signal a condition that is not of type SERIOUS-CONDITION, which users can handle to eg. bypass the lock, and only if it is not handled would we signal a condition inheriting from ERROR.
There are other options too, but ATM these are the most likely looking ones. In case (1) I would also like to add a dynamically scoped symbol-granularity bypassing mechanism, eg. WITHOUT-SYMBOL-PACKAGE-LOCKS to provide the essential functionality.