Deprecated Interfaces
*********************

This chapter documents the deprecation process used for SBCL interfaces, and lists legacy interfaces in various stages of deprecation.

This should not be confused with those things the ANSI Common Lisp standard calls ``deprecated'': the entirety of ANCL CL is supported by SBCL, and none of those interfaces are subject to censure.

Why Deprecate?
==============

While generally speaking we try to keep SBCL changes as backwards compatible as feasible, there are situations when existing interfaces are deprecated:

  * Broken Interfaces

     Sometimes it turns out that an interface is sufficiently misdesigned that fixing it would be worse than deprecating it and replacing it with another.

     This is typically the case when fixing the interface would change its semantics in ways that could break user code subtly: in such cases we may end up considering the obvious breakage caused by deprecation to be preferable.

     Another example are functions or macros whose current signature makes them hard or impossible to extend in the future: backwards compatible extensions would either make the interface intolerably hairy, or are sometimes outright impossible.

  * Internal Interfaces

     SBCL has several internal interfaces that were never meant to be used in user code -- or at least never meant to be used in user code unwilling to track changes to SBCL internals.

     Ideally we'd like to be free to refactor our own internals as we please, without even going through the hassle of deprecating things. Sometimes, however, it turns out that our internal interfaces have several external users who aren't using them advicedly, but due to misunderstandings regarding their status or stability.

     Consider a deprecated internal interface a reminder for SBCL maintainers not to delete the thing just yet, even though it is seems unused -- because it has external users.

     When internal interfaces are deprecated we try our best to provide supported alternatives.

  * Aesthetics & Ease of Maintenance

     Sometimes an interface isn't broken or internal, but just inconsistent somehow.

     This mostly happens only with historical interfaces inherited from CMUCL which often haven't been officially supported in SBCL before, or with new extensions to SBCL that haven't been around for very long in the first place.

     The alternative would be to keep the suboptimal version around forever, possibly alongside an improved version. Sometimes we may do just that, but because every line of code comes with a maintenance cost, sometimes we opt to deprecate the suboptimal version instead: SBCL doesn't have infinite developer resources.

     We also believe that sometimes cleaning out legacy interfaces helps keep the whole system more comprehensible to users, and makes introspective tools such as apropos more useful.

What Happens During Deprecation?
================================

Deprecation proceeds in three stages, each lasting approximately a year. In some cases it migh move slower or faster, but year per stage is what we aim at in general.

During each stage warnings (and errors) of increasing severity are signaled, which note that the interface is deprecated, and point users towards any replacements when applicable.

 1. Early Deprecation

     During early deprecation the interface is kept in working condition, but a style-warning will be signalled for uses of it at compile-time.

     The internals may change at this stage: typically because the interface is re-implemented on top of its successor. While we try to keep things as backwards-compatible as feasible (taking maintenance costs into account), sometimes semantics change slightly.

     For example, when spinlock API was deprecated, spinlock objects ceased to exist, and the whole spinlock API became a synonym for the mutex API -- so code using the spinlock API continued working, but silently switched to mutexes instead. However, if someone relied on

     (typep lock 'spinlock)

     returning NIL for a mutexes, trouble could ensue.

 2. Late Deprecation

     During late deprecation the interface remains as it was during early deprecation, but the compile-time warning is upgraded to a full warning.

 3. Final Deprecation

     During final deprecation the symbols still exist, but using the interface will cause not only the compile-time full warning, but also a runtime error.

After final deprecation the interface is deleted entirely.

List of Deprecated Interfaces
=============================

Early Deprecation
-----------------

  * SB-EXT:QUIT

     Deprecated in favor of sb-ext:exit as of 1.0.56.55 in May 2012. Expected to move into late deprecation in May 2013.

     The design of sb-ext:quit proved too broken to fix in a backwards-compatible manner, so it had to be deprecated and replaced.

     Problems with it were manifold: when called in the main thread it cause the entire process to exit. When called in another thread with :recklessly-p it also caused the entire process to exit. However, when called in another thread without :recklessly-p it instead caused that thread to terminate abnormally without terminating the process. Its behaviour versus other threads than the one it was called in was also underspecified, and dependent on things such as the current session. Any conceivable change that would have made it sane would also have silently broken code that depended on the old behaviour.

     Remedy

     For code needing to work with legacy SBCLs, if you were calling quit with :recklessly-p t, use

          (defun system-exit (&optional (code 0))
            (alien-funcall (extern-alien "exit" (function void int)) code))

     instead. In modern SBCLs simply call either sb-posix:exit or sb-ext:exit.

     If you were calling it without :recklessly-p, be advised that your code may not function as expected when called from threads other than the main one (see above) -- in any case, you can support legacy SBCLs using the following conditionalization:

          (defun lisp-exit (&key (code 0) abort)
            #+#.(cl:if (cl:find-symbol "EXIT" :sb-ext) '(and) '(or))
            ;; Assuming process exit is what is desired -- if thread termination
            ;; is intended, use SB-THREAD:ABORT-THREAD instead.
            (sb-ext:exit :code code :abort abort)
            #-#.(cl:if (cl:find-symbol "EXIT" :sb-ext) '(and) '(or))
            (sb-ext:quit :unix-status code :recklessly-p abort))

  * SB-UNIX:UNIX-EXIT

     Deprecated as of 1.0.56.55 in May 2012. Expected to move into late deprecation in May 2013.

     When the SBCL process termination was refactored as part of changes that led to sb-ext:quit being deprecated, sb-unix:unix-exit ceased to be used internally. Since SB-UNIX is an internal package not intended for user code to use, and since we're slowly in the process of refactoring things to be less Unix-oriented, sb-unix:unix-exit was initially deleted as it was no longer used. Unfortuntely it became apparent that it was used by several external users, so it was re-instated in deprecated form.

     While the cost of keeping sb-unix:unix-exit indefinitely is trivial, the ability to refactor our internals is important, so its deprecation was taken as an opportunity to highlight that SB-UNIX is an internal package and SB-POSIX should be used by user-programs instead -- or alternatively calling the foreign function directly if the desired interface doesn't for some reason exist in SB-POSIX.

     Remedy

     For code needing to work with legacy SBCLs, use eg. system-exit as show above in remedies for sb-ext:quit. In modern SBCLs simply call either sb-posix:exit or sb-ext:exit with appropriate arguments.

  * SB-C::MERGE-TAIL-CALLS Compiler Policy

     Deprecated as of 1.0.53.74 in November 2011. Expected to move into late deprecation in November 2012.

     This compiler policy was never functional: SBCL has always merged tail calls when it could, regardless of this policy setting. (It was also never officially supported, but several code-bases have historically used it.)

     Remedy

     Simply remove the policy declarations. They were never necessary: SBCL always merged tail-calls when possible. To disable tail merging, structure the code to avoid the tail position instead.

  * Spinlock API

     Deprecated as of 1.0.53.11 in August 2011. Expected to move into late deprecation in August 2012.

     Spinlocks were an internal interface, but had a number of external users and were hence deprecated instead of being simply deleted.

     Affected symbols: sb-thread::spinlock, sb-thread::make-spinlock, sb-thread::with-spinlock, sb-thread::with-recursive-spinlock, sb-thread::get-spinlock, sb-thread::release-spinlock, sb-thread::spinlock-value, and sb-thread::spinlock-name.

     Remedy

     Use the mutex API instead, or implement spinlocks suiting your needs on top of sb-ext:compare-and-swap, sb-ext:spin-loop-hint, etc.

Late Deprecation
----------------

  * SB-THREAD:JOIN-THREAD-ERROR-THREAD and SB-THREAD:INTERRUPT-THREAD-ERROR-THREAD

     Deprecated in favor of sb-thread:thread-error-thread as of 1.0.29.17 in June 2009. Expected to move into final deprecation in June 2012.

     Remedy

     For code that needs to support legacy SBCLs, use eg.:

          (defun get-thread-error-thread (condition)
            #+#.(cl:if (cl:find-symbol "THREAD-ERROR-THREAD" :sb-thread)
                       '(and) '(or))
            (sb-thread:thread-error-thread condition)
            #-#.(cl:if (cl:find-symbol "THREAD-ERROR-THREAD" :sb-thread)
                       '(and) '(or))
            (etypecase condition
             (sb-thread:join-thread-error
              (sb-thread:join-thread-error-thread condition))
             (sb-thread:interrupt-thread-error
              (sb-thread:interrupt-thread-error-thread condition))))

  * SB-INTROSPECT:FUNCTION-ARGLIST

     Deprecated in favor of sb-introspect:function-lambda-list as of 1.0.24.5 in January 2009. Expected to move into final deprecation in January 2012.

     Renamed for consistency and aesthetics. Functions have lambda-lists, not arglists.

     Remedy

     For code that needs to support legacy SBCLs, use eg.:

          (defun get-function-lambda-list (function)
            #+#.(cl:if (cl:find-symbol "FUNCTION-LAMBDA-LIST" :sb-introspect)
                       '(and) '(or))
            (sb-introspect:function-lambda-list function)
            #-#.(cl:if (cl:find-symbol "FUNCTION-LAMBDA-LIST" :sb-introspect)
                       '(and) '(or))
            (sb-introspect:function-arglist function))

  * Stack Allocation Policies

     Deprecated in favor of sb-ext:*stack-allocate-dynamic-extent* as of 1.0.19.7 in August 2008, and are expected to be removed in August 2012.

     Affected symbols: sb-c::stack-allocate-dynamic-extent, sb-c::stack-allocate-vector, and sb-c::stack-allocate-value-cells.

     These compiler policies were never officially supported, and turned out the be a flawed design.

     Remedy

     For code that needs stack-allocation in legacy SBCLs, conditionalize using:

          #-#.(cl:if (cl:find-symbol "*STACK-ALLOCATE-DYNAMIC-EXTENT*" :sb-ext)
                     '(and) '(or))
          (declare (optimize sb-c::stack-allocate-dynamic-extent))

     However, unless stack allocation is essential, we recommend simply removing these declarations. Refer to documentation on sb-ext:*stack-allocate-dynamic* for details on stack allocation control in modern SBCLs.

  * SB-SYS:OUTPUT-RAW-BYTES

     Deprecated as of 1.0.8.16 in June 2007. Expected to move into final deprecation in June 2012.

     Internal interface with some external users. Never officially supported, deemed unnecessary in presence of write-sequence and bivalent streams.

     Remedy

     Use streams with element-type (unsigned-byte 8) or :default -- the latter allowing both binary and character IO -- in conjunction with write-sequence.

Final Deprecation
-----------------

No interfaces are currently in final deprecation.

Historical Interfaces
=====================

The following is a partial list of interfaces present in historical versions of SBCL, which have since then been deleted.

  * SB-KERNEL:INSTANCE-LAMBDA

     Historically needed for CLOS code. Deprecated as of 0.9.3.32 in August 2005. Deleted as of 1.0.47.8 in April 2011. Plain lambda can be used where sb-kernel:instance-lambda used to be needed.

  * SB-ALIEN:DEF-ALIEN-ROUTINE, SB-ALIEN:DEF-ALIEN-VARIABLE, SB-ALIEN:DEF-ALIEN-TYPE

     Inherited from CMUCL, naming convention not consistent with preferred SBCL style. Deprecated as of 0.pre7.90 in December 2001. Deleted as of 1.0.9.17 in September 2007. Replaced by sb-alien:define-alien-routine, sb-alien:define-alien-variable, and sb-alien:define-alien-type.