Common Lisp package definition - package

In Common Lisp package definition, what is the difference between
(defpackage #:foo
(:use :cl)
(:export #:bar
#:baz))
(in-package #:foo)
and
(defpackage :foo
(:use :cl)
(:export :bar
:baz))
(in-package :foo)
I mean. When I have to use the "#" character? All these symbols are uninternerd, right?

:foo is the syntax for a keyword symbol, and #:foo is the syntax for an uninterned symbol. When a symbol is used primarily to get at the string that is its name (as in defpackage and in-package), I prefer to use uninterned symbols.
Here are the other options:
use a keyword symbol; I don't like how this interns keyword symbols that show up in apropos and other places
use a string; I don't like how this gratuitously breaks Allegro's "modern" mode
use a plain symbol; I don't like how this both interns a symbol, and how it interns it in a potentially random package
Which style you or anyone else uses is a matter of taste.

Related

Common lisp — why isn't this symbol external?

I'm trying to run tests in ASDF, which looks like this:
;;;; foo.asd
(defsystem "foo/tests"
:depends-on ("foo"
"fiveam")
:components ((:module "tests"
:components
((:file "main"))))
:perform (test-op (op c) (symbol-call :fiveam '#:run! 'foo/tests:all-tests))
And my tests/main.lisp file starts off like this:
;;;; tests/main.lisp
(defpackage foo/tests
(:use :cl
:foo
:fiveam)
(:export :#run! :#all-tests))
(in-package :foo/tests)
When I run (asdf:test-system 'foo) in my REPL, I get dropped into the debugger with a LOAD-SYSTEM-DEFINITION-ERROR. The debugger is complaining that The symbol "ALL-TESTS" is not external in the FOO/TESTS package.
However, I am clearly exporting the symbol in the foo/tests package. Can somebody please tell me what I'm missing here and why the Lisp compiler isn't seeing the external symbol? Thank you very much.
The syntax for an uninterned symbol is #:foo, not :#foo.
You also need to resolve the symbols in the :perform form at run-time, e. g. through uiop:find-symbol*, just like you use uiop:symbol-call there.
:perform (test-op (op c)
(symbol-call :fiveam '#:run!
(find-symbol* '#:all-tests '#:foo/tests)))
Or, since you seem to export a run! function from your test package, you might want to call that instead of fiveam:run!:
:perform (test-op (op c)
(symbol-call '#:foo/tests '#:run!))

:EXPORT from Package in Common Lisp

I have defined a package like the following:
(defpackage :thehilariouspackageofamirteymuri
(:nicknames ampack amir teymuri)
(:use common-lisp)
(:export say-hi-to))
(in-package :amir)
(defun say-hi ()
"Docstring"
"Hello")
(defun say-hi-to (who)
(concatenate 'string (say-hi) " " who " from " (package-name *package*) "!"))
Now changing to the package also the #'say-hi is accessible:
(in-package :amir)
(say-hi) ; -> "Hello"
(say-hi-to "World") ; -> "Hello World from THEHILARIOUSPACKAGEOFAMIRTEYMURI!"
Isn't the export keyword telling to make things external for the package? Why is the non-external #'say-hi also exported?
Since you are using again (in-package :amir) the following forms are evaluated in that package, so that you can use all the function defined in it. To check which definitions are exported, you should switch to a different package.
Let’s try the standard package CL-USER:
AMIR> (in-package :cl-user)
#<Package "COMMON-LISP-USER">
CL-USER> (say-hi)
Undefined function SAY-HI called with arguments ("world") ; as expected, but...
CL-USER> (say-hi-to "world")
Undefined function SAY-HI-TO called with arguments ("world") ; ops!!
CL-USER> (amir:say-hi-to "world)
"Hello world from COMMON-LISP-USER!"
CL-USER> (amir:say-hi)
Reader error: No external symbol named "SAY-HI" in package #<Package "THEHILARIOUSPACKAGEOFAMIRTEYMURI"> .
The reason is that exporting a symbol does not mean that we can use it without qualiyfing its package. As you can see, however, only symbols exported from a packgage can be used with “:”. If you want to use the symbol without the package name as prefix, you must import it before.
So, let’s start again.
CL-USER> (defpackage :another-package (:use :amir))
#<Package "ANOTHER-PACKAGE">
CL-USER> (in-package :another-package)
#<Package "ANOTHER-PACKAGE">
ANOTHER-PACKAGE> (say-hi-to "world")
"Hello world from ANOTHER-PACKAGE!"
ANOTHER-PACKAGE> (say-hi)
Undefined function SAY-HI called with arguments ()
Inside ANOTHER-PACKAGE you can now use the exported symbol without qualifications.
In general, exporting and importing symbols in packages in Common Lisp is not so intuitive, and a good description of all the intricacies of packages can be found at the link cited in the other answer.
Check the difference without changing the current package. You will find more information e.g. here

Shadowing (redefining) symbol in commmon-lisp package ends up with errors

I found out that my package has a problem shadowing delete from the common-lisp package. I have tried various types of shadowing, but none of them worked for me. I guess I'm using it wrong, but still can't make it to work.
I have shortened the code just to show the problem part
This solution throws error: Redefining macro DELETE visible from package COMMON-LISP.
(in-package "CL-USER")
(defpackage :simple-db
(:use :common-lisp)
(:shadow :delete)
(:export :delete))
Another solution throws error: Duplicated symbols in "SIMPLE-DB" defpackage: "DELETE".
(in-package "CL-USER")
(defpackage :simple-db
(:use :common-lisp)
(:shadow :delete)
(:export :delete)
(:shadowing-import-from :simple-db :delete))
The problem you are having is probably not in your package definition (the first one is fine), it's in packages which want to use your package, and also to use CL. Those packages end up with references both to CL:DELETE and SIMPLE-DB:DELETE. Given your definition:
(defpackage :simple-db
(:use :common-lisp)
(:shadow :delete)
(:export :delete))
Then any package which wants to use both SIMPLE-DB and CL will get an error.
(defpackage :simple-db-user
;; this is an error
(:use :common-lisp :simple-db))
You will also see this in any package (for instance CL-USER) if you simply say (use-package :simple-db).
The traditional way to resolve this error is use SHADOWING-IMPORT to pick the symbol you want:
(defpackage :simple-db-user
(:use :common-lisp :simple-db)
(:shadowing-import-from :simple-db :delete))
or, in an existing package:
(shadowing-import '(:delete) :simple-db)
There are (I think) nicer solutions which involve defining packages which are 'like' CL but which redefine some symbols, and which you then treat like a mutant CL package, but those solutions require macrology to make them easy to use which I won't give here.
I don't see a problem:
* (cl:defpackage :simple-db
(:use :common-lisp)
(:shadow :delete)
(:export :delete))
#<PACKAGE "SIMPLE-DB">
* (defun simple-db:delete (foo) foo)
SIMPLE-DB:DELETE
* (describe 'simple-db:delete)
SIMPLE-DB:DELETE
[symbol]
DELETE names a compiled function:
Lambda-list: (FOO)
Derived type: (FUNCTION (T) (VALUES T &OPTIONAL))
Source form:
(SB-INT:NAMED-LAMBDA SIMPLE-DB:DELETE
(FOO)
(BLOCK SIMPLE-DB:DELETE FOO))

External vs Internal Symbols in Common Lisp Package

What is the difference between them in the context of a Common Lisp package? I am reading through SLIME documentation and some commands mention that extensively.
What is the syntax ? The symbols you export are external.
(in-package :cl-user)
(defpackage str
(:use :cl)
(:export
:trim-left
))
(in-package :str)
;; exported: can be accessed with `str:trim-left`.
(defun trim-left (s)
"Remove whitespaces at the beginning of s. "
(string-left-trim *whitespaces* s))
;; forgot to export: can still access it with `str::trim-right`.
(defun trim-right (s)
"Remove whitespaces at the end of s."
(string-right-trim *whitespaces* s))
The author of a Common Lisp package can export a symbol for the user of the package. Then the symbol is an external symbol and you can access it with package-name:external-symbol-name.
Internal symbols are not meant for the user but can be accessed with package-name::symbol-name
More explanations are in Peter Seibel's book and Common Lisp the Language

Use package shadowing symbols

For instance I have this package definition which shadows COMMON-LISP:LISTEN :
(defpackage :shadows
(:use :common-lisp)
(:shadow #:listen)
(:export #:listen))
And then I want to use this package from another package, say
(defpackage :light
(:use :common-lisp
:shadows))
What is the purpose of shadow if I cannot actually override Common Lisp symbols when using the package ?
Simple
The :shadow argument to defpackage
affects the definition of the package shadows,
not the later use of shadows in light.
You need to use shadowing-import:
(defpackage #:shadows
(:use #:common-lisp)
(:shadow #:listen)
(:export #:listen))
(defpackage #:light
(:shadowing-import-from #:shadows #:listen)
(:use #:common-lisp #:shadows))
(eq 'light::listen 'shadows:listen)
==> T
(describe 'light::listen)
==>
SHADOWS:LISTEN is the symbol SHADOWS:LISTEN, lies in #<PACKAGE SHADOWS>,
is accessible in 2 packages LIGHT, SHADOWS.
#<PACKAGE SHADOWS> is the package named SHADOWS.
It imports the external symbols of 1 package COMMON-LISP and
exports 1 symbol to 1 package LIGHT.
Bulk
If you need to do bulk shadowing, you would need to use individual functions
(make-package,
import,
export,
shadow,
use-package):
(defparameter *my-shadow-list* '(#:car #:cdr))
(make-package '#:my-package :use nil)
(import *my-shadow-list* '#:my-package)
(export *my-shadow-list* '#:my-package)
(shadow *my-shadow-list* '#:my-package)
(use-package '#:cl '#:my-package)
(make-package '#:my-user)
(shadowing-import *my-shadow-list* '#:my-user)
(use-package '(#:cl #:my-package) '#:my-user)
(describe 'my-user::car)
==>
MY-PACKAGE:CAR is the symbol MY-PACKAGE:CAR, lies in #<PACKAGE MY-PACKAGE>,
is accessible in 2 packages MY-PACKAGE, MY-USER.
#<PACKAGE MY-PACKAGE> is the package named MY-PACKAGE.
It imports the external symbols of 1 package COMMON-LISP and
exports 2 symbols to 1 package MY-USER.
You might find macroexpand-1 useful in decising how get where you need to go:
(macroexpand-1 '(defpackage #:light
(:shadowing-import-from #:shadows #:listen)
(:use #:common-lisp #:shadows)))
==>
(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
(SYSTEM::%IN-PACKAGE "LIGHT" :NICKNAMES 'NIL :USE 'NIL :CASE-SENSITIVE NIL
:CASE-INVERTED NIL)
(SYSTEM::SHADOWING-IMPORT-CERROR "LISTEN" "SHADOWS" NIL "LIGHT")
(USE-PACKAGE '("COMMON-LISP" "SHADOWS") "LIGHT") (FIND-PACKAGE "LIGHT")) ;
T
PS. Shadowing ANSI CL standard names is not a very good idea for your code readability.
OK so there actually is a handy way to do this.
In my many-shadows package I export a shadowing-import-from function. It looks like this :
(defun shadowing-import-from ()
`(:shadowing-import-from :many-shadows
,#(package-shadowing-symbols :many-shadows)))
And then, in the light defpackage I just READ-EVAL it :
(defpackage :light
(:use :common-lisp
:many-shadows)
#.(many-shadows:shadowing-import-from))
So it is explicit that something was shadowed and that I want to use the symbols from many-shadows in priority. And it is short enough to be documented and used pragmatically.
Thank you #sds for pointing me to :shadowing-import-from.
What is the purpose of shadow if I cannot actually override Common Lisp symbols when using the package?
The purpose of a package having a list of shadowing symbols is to resolve conflicts arising from package use by that package. Shadowing has no effect on anything exported.
When a package uses others, conflicts can arise when two or more used packages export a symbol by the same name. Similarly, conflicts can also arise between a used package and symbols in the local package. These conflicts are treated as errors. On a symbol-by-symbol basis, shadowing squelches these conflicts. A symbol, which is present in the package, is added to its list of shadowing symbols. Any conflict is then silently resolved in favor of that symbol.
Being a shadowing symbol doesn't bestow any special powers on a symbol when it is regarded from outside the package where it has that status.
For each package, we have to separately arrange the "visibility stack", including its own shadowing symbols, if necessary.

Resources