Common Lisp exporting symbols from packages

common lisp in-package
common lisp require
common lisp package manager
practice common lisp
common lisp tutorial
common lisp loop on
defpackage android
learn common lisp

Is there a short way of exporting all the symbols from a package or is it the only way to do it in defpackage. I generally write my code in a file foo.lisp which generally starts with (in-package :foo) and put the package definition to a file package.lisp which generally involves something like this:

(in-package :cl-user)

(defpackage :foo
  (:use :cl)
  (:documentation "Bla bla bla."
  (:export :*global-var-1*
           :*global-var-2*
           :function-1
           :function-2
           :struct
           :struct-accessor-fun-1
           :struct-accessor-fun-2
           :struct-accessor-fun-3
           :struct-accessor-fun-4))

My question is: Designing simply an interface using some global variables and functions may not be adequate sometimes, and you have to export some structures. When this is the case, if you don't simply export accessor functions of this struct, you can not manipulate objects of these struct. So, is there an easy way for accomplishing this effect without manually exporting all these accessor functions?

Once the package is created, and all symbols in it created, e.g., by loading your code that implements the package, you can export any symbols you like, e.g., to export all:

(do-all-symbols (sym (find-package :foo)) (export sym))

You'll probably be happier with

(let ((pack (find-package :foo)))
  (do-all-symbols (sym pack) (when (eql (symbol-package sym) pack) (export sym))))

which won't try re-exporting everything from used packages.

Programming in the Large: Packages and Symbols, In addition to causing it to be inherited by using packages, exporting a symbol For example, the name *PACKAGE* is exported from COMMON-LISP --if you  Common Lisp provides some macros to iterate through the symbols of a package. The two most interesting are: DO-SYMBOLS and DO-EXTERNAL-SYMBOLS. DO-SYMBOLS iterates over the symbols accessible in the package and DO-EXTERNAL-SYMBOLS only iterates over the external symbols (you can see them as the real package API).

Evaluating the macroexpanded code, I get an error for the last nil in the defclass form if no class option is supplied and additional errors as the symbols of the export function have to be quoted. Here is a corrected version which seems to work on my common lisp system (sbcl):

(defmacro def-exporting-class (name (&rest superclasses) (&rest slot-specs)
                               &optional class-option)
  (let ((exports (mapcan (lambda (spec)
                           (when (getf (cdr spec) :export)
                             (let ((name (or (getf (cdr spec) :accessor)
                                             (getf (cdr spec) :reader)
                                             (getf (cdr spec) :writer))))
                               (when name (list name)))))
                         slot-specs)))
    `(progn
       (defclass ,name (,@superclasses)
         ,(append 
           (mapcar (lambda (spec)
                     (let ((export-pos (position :export spec)))
                       (if export-pos
                       (append (subseq spec 0 export-pos)
                           (subseq spec (+ 2 export-pos)))
                       spec)))
               slot-specs)
           (when class-option (list class-option))))
       ,@(mapcar (lambda (name) `(export ',name))
                 exports))))


(macroexpand-1
 '(def-exporting-class test1 nil
   ((test-1 :accessor test-1 :export t)
    (test-2 :initform 1 :reader test-2 :export t)
    (test-3 :export t))))

(PROGN
 (DEFCLASS TEST1 NIL
           ((TEST-1 :ACCESSOR TEST-1) (TEST-2 :INITFORM 1 :READER TEST-2)
            (TEST-3)))
 (EXPORT 'TEST-1)
 (EXPORT 'TEST-2))

CLHS: Function EXPORT, Description: export makes one or more symbols that are accessible in package (whether directly or by inheritance) be external symbols of that package. If any of the symbols is already accessible as an external symbol of package, export has no effect on that symbol. That collection of symbols is called a package. A package is a collection of Lisp symbols with the property that no two symbols in the collection have the same name. Unfortunately, that is more or less the last aspect of packages that is simple and straightforward. From here on out things get rather hairier. 3. Interning The act of putting a

Vsevolod's post inspired me to post a macro as well:

(defmacro defpackage! (package &body options)
  (let* ((classes (mapcan 
                    (lambda (x) 
                      (when (eq (car x) :export-from-classes)
                        (cdr x)))
                    options))
         (class-objs (mapcar #'closer-common-lisp:find-class classes))
         (class-slots (mapcan #'closer-mop:class-slots class-objs))
         (slot-names (mapcar #'closer-mop:slot-definition-name class-slots))
         (slots-with-accessors
           (remove-duplicates (remove-if-not #'fboundp slot-names))))
    (setf options (mapcar
                    (lambda (option)
                      (if (eq (car option) :export)
                        (append option 
                                (mapcar #'symbol-name slots-with-accessors))
                        option))
                    options))
    (setf options (remove-if 
                    (lambda (option)
                      (eq (car option) :export-from-classes))
                    options))
    `(defpackage ,package ,@options)))

To use:

CL-USER> 
(defclass test-class ()
  ((amethod :accessor amethod :initarg :amethod :initform 0)
   (bmethod :reader bmethod :initform 1)))
#<STANDARD-CLASS TEST-CLASS>
CL-USER> 
(closer-mop:ensure-finalized  (find-class 'test-class))
#<STANDARD-CLASS TEST-CLASS>
CL-USER> 
(macroexpand-1 
  `(defpackage! test-package
     (:export "symbol1")
     (:export-from-classes test-class)))
(DEFPACKAGE TEST-PACKAGE
  (:EXPORT "symbol1" "AMETHOD" "BMETHOD"))
T
CL-USER> 

This isn't well tested, and I'm still learning the MOP API, so there may be much better/cleaner ways to achieve the same goal here (especially the fboundp kludge). Also, this only looks for accessor functions on a class. There are also methods that specialize on a class. You could use the MOP to find those as well...

CLHS: Function EXPORT, All of these packages are checked for name conflicts: (export s p) does (find-​symbol (symbol-name s) q) for each package q in (package-used-by-list p). Note that  (defpackage :package-name (:use :common-lisp ) (:export :symbol1 :symbol2 ) ) Where, package-name is the name of the package. The :use keyword specifies the packages that this package needs, i.e., packages that define functions used by code in this package. The :export keyword specifies the symbols that are external in this package.

There is a way with the cl-annot package. Its export-slots, export-accessors, export-constructors allow to automatically export them. It works for classes and structures.

For example,

@export-accessors
(defclass foo ()
     ((bar :reader bar-of)
      (bax :writer bax-of)
      (baz :accessor baz-of)))

is equivalent to

(progn
  (export '(bar-of bax-of baz-of))
  (defclass foo ()
     ((bar :reader bar-of)
      (bax :writer bax-of)
      (baz :accessor baz-of))))

11.4. Exporting and Importing Symbols, Common Lisp the Language, 2nd Edition. next · up · previous contents index. Next: Name Conflicts Up: Packages Previous: Translating Strings to. 11.4. CL-USER> common-lisp:*package* #<The COMMON-LISP-USER package> You can even use COMMON-LISP's nickname, CL. CL-USER> cl:*package* #<The COMMON-LISP-USER package> But *X* isn't a symbol in COMMON-LISP, so you if type this: CL-USER> (defvar *x* 10) *X* the reader reads DEFVAR as the symbol from the COMMON-LISP package and *X* as a symbol in COMMON-LISP-USER.

11. Packages, Common Lisp addresses this problem through the package system, derived from an It is possible to refer to symbols in packages other than the current one external only if they appear explicitly in an export command for the package. :shadowing-import-from. The symbols named by the argument symbol-names are found (involving a lookup as if by find-symbol) in the specified package-name. The resulting symbols are imported into the package being defined, and placed on the shadowing symbols list as if by shadowing-import.

[PDF] The Idiot's Guide to Common Lisp Packages, There are two things to note about exporting symbols. First, a symbol can be exported from any package in which that symbol is interned, not just its home package  Function SYMBOL-PACKAGE. Syntax: symbol-package symbol => contents. Arguments and Values: symbol---a symbol. contents---a package object or nil. Description: Returns the home package of symbol. Examples:

[PDF] The Complete Idiot's Guide to Common Lisp Packages, Common Lisp provides a standard mechanism for doing this. Every package maintains a list of symbols that are intended to be used by other packages. This list is called the exported symbol list of that package, and to add a symbol to that package you use the function EXPORT. The conduit-packages Reference Manual. This is the conduit-packages Reference Manual, generated automatically by Declt version 3.0 "Montgomery Scott" on Wed Mar 25 17:53:19 2020 GMT+0.

Comments
  • Really nice! I never would have thought to add and consume a slot (:export) in the standard CLOS slot definition.