This one is a little bit embarrassing, but I have been stuck with this one way longer than I want to admit.
I would like to generate a macro that automatically shadow a symbol if it is found in some existing package. I am only using :common-lisp package, and will shadow several functions from the standard.
I have previously kept a list of shadowed and exported symbols, but I would like not to keep those lists. Instead, I would prefer to shadow the symbol from a macro, so I can have both shadow and export declaration together with the definition. It seems very simple, however, whichever way I implemented it, I am either violating package locks, or my symbol is undefined, or something else. To start with, here is a package def:
(in-package :cl-user)
(uiop:define-package :foo-package
(:nicknames :foo)
(:use :common-lisp)
(:shadow #:defun))
(in-package :foo)
The test function does nothing, just a small wrapper for the test:
(defun make-string (length init)
(cl:make-string length :initial-element init))
My first attempt looked like this:
(cl:defmacro defun (name arglist &optional docstring &rest body)
`(progn
(when (symbol-package ',name)
(shadow ',name))
(cl:defun ,name ,arglist ,docstring ,@body)
(export '(,name))))
However, that results in a package lock violation with SBCL, so shadow function obviously is not taking effect before I try to re-define the function with cl:defun.
Wrapping it in
(eval-when (:compile-toplevel :load-toplevel :execute)
, to make it available at compile time didn’t help.
Another attempt was using a generator:
(eval-when (:compile-toplevel :load-toplevel :execute)
(cl:defmacro defun (name args &optional docstring &rest body)
(macrolet ((export-it (name args &optional docstring &rest body)
`(progn
(when (symbol-package ',name)
(shadow ',name))
(cl:defun ,name ,args ,docstring ,@body)
(export '(,name) *package*))))
`(export-it ,name ,args ,docstring ,@body))))
This gives me common-lisp:make-string unbound:
debugger invoked on a UNBOUND-VARIABLE @10039FFD22 in thread
#<THREAD “main thread” RUNNING {10044982F3}>: The variable MAKE-STRING is unbound.
I have tried to generate a lambda and funcall it, but without much success either.
If I shadow make-string manually from repl: (shadow 'make-string)
, I can afterwards redefine and export make-string without problems.
Seems I misunderstand something more fundamental there.
By the way, I was reading M. Cracauers Compile Time Programming article, and thought it was a nice idea to keep everything at the same place, but I think my familiarity with macros and compile-time vs runtime evaluation is not where it should be.
I understand I can use SBCL specific things to temporary remove package locks, but ‘shadow’ and ‘symbol-package’ or ‘find-package’ and ‘find-symbol’ which I initially used to check if a symbol is interned in :common-lisp package, should be more portable.