Skip to content
Packages and Modules
step 1/5

Reading — step 1 of 5

Learn

~2 min readPackages, Sequences, Pathnames

Common Lisp's namespace system is packages. Each symbol belongs to a package; you import or qualify to access symbols from other packages.

Defining a package

(defpackage :my-app
    (:use :common-lisp)
    (:export #:greet #:farewell))

(in-package :my-app)

(defun greet (name)
    (format nil "Hello, ~a!" name))

(defun farewell (name)
    (format nil "Bye, ~a!" name))

(defun helper ()                    ; not exported — package-private
    "internal stuff")
  • :use :common-lisp imports every symbol from the standard package — get defun, format, let, etc.
  • :export lists what's PUBLIC. Symbols not exported are accessible only from inside the package.

Accessing symbols

From outside :my-app:

(my-app:greet "Ada")                ; one colon — exported
(my-app::helper)                    ; two colons — internal (don't do this)

Importing

(defpackage :my-other
    (:use :common-lisp :my-app))    ; pull in all of my-app's exports

(in-package :my-other)
(greet "Bob")                        ; works directly — was imported

Or selectively:

(defpackage :my-other
    (:use :common-lisp)
    (:import-from :my-app #:greet))

In-package

A file usually starts with:

(in-package :my-app)

After that, all definitions go in that package. Without it, definitions land in :cl-user (the REPL package).

Common pitfalls

Symbol equality across packages:

(eq 'foo 'my-app::foo)              ; nil if 'foo is in cl-user, not my-app

A symbol's identity is its package + name. my-app::foo and cl-user::foo are different symbols.

Read-time package: when you read 'foo at the REPL, it goes into the current package (the one set by in-package). Files set their package; the REPL's package is :cl-user by default.

Standard packages

  • :common-lisp (alias :cl) — language built-ins
  • :common-lisp-user (:cl-user) — REPL default
  • :keyword — where keywords (:foo) live

Quicklisp packages

Real Common Lisp projects use Quicklisp (the package manager) and ASDF (the build tool):

(ql:quickload :alexandria)          ; download + load
(alexandria:hash-table-keys table)

Typical project layout:

  my-app/
    my-app.asd                      ; ASDF system definition
    package.lisp                     ; defpackage forms
    src/
      core.lisp
      utils.lisp

my-app.asd:

(defsystem :my-app
    :depends-on (:alexandria)
    :components ((:file "package")
                 (:file "core" :depends-on ("package"))))

(asdf:load-system :my-app) loads everything.

For Judge0 we run single-file programs — packages don't really show up. But for any real Lisp project, this is the foundation.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…