Options

The following options are available. Each of these are implemented as a call to the corresponding package manipulation function. Repeated evaluations of the DEFPACKAGE+ form are the same as repeatedly calling each function in sequence, and the behavior of such is stated below:

:use PACKAGES...: PACKAGES are inherited as per USE-PACKAGE.
Notably, this is different from defpackage's :use, because it
only adds packages.

:use-only PACKAGES...: PACKAGES are inherited exclusively; any
packages not named are removed as per UNUSE-PACKAGE. This is like
defpackage's :use.

:export SYMBOLS...: Ensure and export SYMBOLS. Unlike
defpackage, it is not an error or warning for this list to be
incomplete.

:export-only SYMBOLS...: Ensure and export SYMBOLS. Any symbols
not named will be unexported.

:export-warning SYMBOLS...: Ensure and export SYMBOLS. If there
are symbols already exported that are not named, issue a warning.

:documentation STRING: Set the package documentation string to
STRING.

:shadowing-import-from PACKAGE SYMBOLS...: Import SYMBOLS from
PACKAGE, and add the to the shadowing symbols list.

:nicknames NAMES...: Make NAMES the nicknames. Nicknames not
named will be removed.

:intern SYMBOLS...: Intern SYMBOLS if they are not already
accessible.

Package definition itself (i.e. the (defpackage+ NAME) part) happens via ENSURE-PACKAGE; the package will be created unless one already exists with the given name.

Differences with defpackage

For the most part, defpackage+ is simply a more convenient defpackage. You can likely use them interchangeably. However, there are some notable differences:

Order is significant: Unlike defpackage, which allows you to
specify options in any order, and executes them in a specific order,
defpackage+ executes options in the order given.

Some options such as :use and :export have more permissive
behavior depending on your Lisp.

The :use list is by default NIL. You must specify all packages,
such as CL.

There is no :size.

There may be other effective differences due to the above.

Extensibility

All options to defpackage+ are implemented via calls to
DEFPACKAGE+-DISPATCH:

defpackage+-dispatch OPTION PARAMS PACKAGE

OPTION is the car of the option, PARAMS is the cdr, and
PACKAGE is the name of the package as specified to defpackage+.
Specialize on OPTION. Keywords and symbols from COMMON-LISP are
reserved by defpackage-plus for internal use.

Note, this function does not return an expansion as for a macro.
Rather, defpackage+ itself expands into a series of calls to this
function. This makes extensibility much easier.

Package Manipulation Functions

Numerous additional functions are provided in addition to what Common Lisp already provides. These are identical to, and used to implement, the corresponding defpackage+ options.

ensure-use-only, ensure-package, ensure-nicknames,
ensure-export, ensure-export-only, ensure-export-warning:
These are all functions which ensure the relevant package state
(including ensure-package, which ensures the package named
exists).

import-from, shadowing-import-from: These provide a "-FROM" form
to complement the Common Lisp functions.

import-external-from: The function to complement the
:import-external option.

Simply append an appropriate version number to your package. When you
wish to introduce significant (i.e., API-incompatible) changes, simply
create a new package with defpackage+ with a higher version, and use
the various :inherit options to push forward anything that will
not change.

This does nothing fancy: it simply imports and exports all external
symbols from :system-1, except FUNCTION-3. At this point, a
differentFUNCTION-3 is exported, and it may be defined in
whatever new way that's desired.

Both versions may exist simultaneously, even share code, and vary in
whatever way the developer needs. Simple, but effective.

In this case FUNCTION-3 may be an entirely different interface
intended to replace FUNCTION-2. However, FUNCTION-1 will remain
unchanged and available.

Users will simply do the following:

(defpackage+ user-package-1
(:use ... #:my-package-2))

This will ensure they see only the relevant 2 symbols. Of
course, users using defpackage+ is not strictly necessary, but it
may be useful in the following examples.

Not all users may, of course, wish to import all of your symbols into
their packages, for all the regular reasons. And typing
my-package-2: before every symbol may be a bit onerous to some. The
following is also a possibility:

This resolves nothing; changing the current package will still break
everyone's code, defeating the point. Requiring people to figure out
after the fact which version works with their code is even worse.
You change things wildly. Much code rot ensues.

Import everything always. It may occur to you to do the
following, if you are unfamiliar with how packages and symbols work:

The fact FUNCTION-1 is being redefined while "in" MY-PACKAGE-2
is irrelevant: FUNCTION-1 is still imported from MY-PACKAGE-1,
and you are redefining the old function here. What you should
have done was :inherit-except and exported a new version.

Import symbols in ‘SYMBOL-NAME-LIST‘ from ‘FROM-PACKAGE‘ into
‘PACKAGE‘, but only if they are external to ‘FROM-PACKAGE‘. It is an
error if any symbol named in ‘SYMBOL-NAME-LIST‘ is not accessible in
‘FROM-PACKAGE‘, or if the symbol is not external to ‘FROM-PACKAGE‘.

Import/export some external symbols from ‘FROM-PACKAGE‘. This is like
‘IMPORT-FROM‘, except symbols in ‘SYMBOL-LIST‘ are *also exported*
from ‘PACKAGE‘. It is an error if any symbols in ‘SYMBOL-LIST‘ are
not external to ‘FROM-PACKAGE‘.