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 ?
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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With