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

462 Views Asked by At

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))
2

There are 2 best solutions below

2
Rainer Joswig On

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))
0
AudioBubble On

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.