Then again, I seem to fiddle too much with packages lately. In
particular, currently I am experimenting with a new work flow of
Package Forms during Development
When writing new Lisp code, I start with just the essentials of a new package in my current Emacs buffer:
(defpackage #:foo (:use #:cl))
(This is basically what I get with C-x C-r P RET RET RET.)
During development, I find it distracting to remind myself of
keeping the package form up-to-date. When I decide to
import new symbols or shadow others I manipulate the package object
directly, instead of updating the above
and reevaluating it:
(use-package 'cl-fred), etc.. All this
can be automated with a few editor key bindings, and the effects are
visible in my working environment immediately.
At this point, I seldom bother with export lists, because I might change names around later on, and also I am working mostly in the package.
At the end of the hacking session, I can just
(defpackage-form 'foo) to get the current
state of package
FOO conveniently as
DEFPACKAGE form, which I can then use to replace the
initial stub. Eventually, if the code grows big enough to split it
up, I move the package form to a separate
At least in the first iteration, the export list is likely still
incomplete, so I can choose to include all symbols
package is the package I am working on, nicely sorted by name.
Then I remove those symbols which are not meant for exporting. Like
that, it is easy to bulk export many symbols at once. As a common
convention, symbols starting with
% are meant to be
internal. They can be omitted from the export list automatically.
Incremental updates of package forms are a little trickier, though. The generated form could, for example, be compared to the original with diff-sexp. I have not automated that stage much yet. If there are only few additions, it is probably easier to just add them manually.
Otherwise, I could imagine
which checks whether the export list of a package matches
DEFPACKAGE form in packages.lisp (or
wherever it is stored—this could be figured out with source
locations), and some more automation and integration with Emacs.
Very unfortunately, some loss of information occurs on the round trip from package form to object and back:
- Reader conditionals inside
DEFPACKAGEforms cannot be recreated easily. Neither can comments, for what it's worth.
- There appears to be no way to figure out which package a symbol
was actually imported from. For example, if we
FOOand then import
FOO:NILinto some other package
BAR, it will appear the same as if
CL:NILwas imported directly into
- The default
:USElist (i.e., when none is specified) is implementation dependent, which naturally can cause some implementation dependent packages to show up in this list.