:EXPORT from Package in Common Lisp - package

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

Related

Suppressing Symbol Package Prefixes (Common Lisp)

When printing out object names which are interned in one package, but referenced from another package, the print name will include the full package name. For example, the following interaction interns the symbol X in PKG1, and prints its value from CL-USER:
* *package*
#<PACKAGE "COMMON-LISP-USER">
* (defpackage :pkg1 (:use :cl))
#<PACKAGE "PKG1">
* (in-package :pkg1)
#<PACKAGE "PKG1">
* (defvar x '(a b c))
X
* (in-package :cl-user)
#<PACKAGE "COMMON-LISP-USER">
* pkg1::x
(PKG1::A PKG1::B PKG1::C)
Sometimes for diagnostic/debugging reasons, I would like to printout external symbols without their package prefixes. In this case the printout would then look like (A B C). For complicated or nested objects where you know what the names mean, the package prefixes can make the printout hard to read, especially if there are multiple packages. Can the prefixes be temporarily suppressed for printout?
No, but you can elide the prefixes of one package by temporarily binding *package* to it for the printout.
Example:
(let ((*package* (find-package :pkg1)))
(print pkg1:*x*))
Since *package* is globally dynamic, this affects everything called inside (i. e. in the dynamic extent of its invocation) this let form but doesn't affect anything outside.

Common Lisp appending package name to quoted keys in macros

I noticed the following behavior in Common Lisp (at least using SBCL), which I was able to reduce it to the following:
Suppose I have the following Macro:
(defpackage "MY-TEST"
(:use "COMMON-LISP")
(:export :appended
:not-appended))
(in-package :MY-TEST)
(defmacro not-appended ()
`(list ':type 'array))
(defmacro appended ()
`(list ':type 'something-else))
The following is the output:
* (my-test:not-appended)
(:TYPE ARRAY)
* (my-test:appended)
(:TYPE MY-TEST::SOMETHING-ELSE)
Notice that in the second macro, the namespace is preceding the "SOMETHING-ELSE".
Questions:
Why is t the case that they differ? Honestly I was expecting the behavior of the "not-appended" macro. Is that because "array" is somehow known to Common Lisp?
If yes, then where can I find the other known keywords?
Note that this is fully unrelated to macros and is an effect of packages, symbols and how symbols are printed:
The package `MY-TEST':
CL-USER 2 > (defpackage "MY-TEST"
(:use "COMMON-LISP")
(:export :appended
:not-appended))
#<The MY-TEST package, 0/16 internal, 2/16 external>
Making the package the current package by calling in-package:
CL-USER 3 > (in-package :MY-TEST)
#<The MY-TEST package, 0/16 internal, 2/16 external>
Let's compute a list of the symbols array and foo. See how the REPL prints it as (ARRAY FOO) because both symbols are accessible in package MY-TEST.
MY-TEST 4 > (list 'array 'foo)
(ARRAY FOO)
Making CL-USER the current package:
MY-TEST 5 > (in-package :cl-user)
#<The COMMON-LISP-USER package, 151/256 internal, 0/4 external>
Now let's get the second last value and see how the REPL prints it:
CL-USER 6 > **
(ARRAY MY-TEST::FOO)
ARRAY is printed without package prefix, because it is the same symbol from the package COMMON-LISP (which was used in the package MY-TEST). FOO is printed with the package prefix MY-TEST, because it is an internal symbol in that package - it was interned there, because then the current package was MY-TEST. There are two colons, because the symbol FOO is not exported from the package MY-TEST and it is also not imported into the package CL-USER.
The package "CL" and "CL-USER" contain all the symbols from the programming language Common Lisp - thus importing "CL" into your own package makes all of those symbols available in that package, too.
CL-USER 7 > (let ((l '()))
(do-symbols (sym (find-package "CL") l)
(pushnew sym l)))
(MAKE-ARRAY INVOKE-DEBUGGER STRING-TRIM WILD-PATHNAME-P UNREAD-CHAR RESTART-BIND ...

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.

Common Lisp package definition

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.

Resources