Let me consider two files with packages in it:
------------------------------------------------------------------------
package-1.cl
------------------------------------------------------------------------
(defpackage :package-1
(:use :common-lisp))
(in-package :package-1)
(defvar *my-var* 1)
------------------------------------------------------------------------
package-2.cl
------------------------------------------------------------------------
(defpackage :package-2
(:use :common-lisp))
(in-package :package-2)
(defvar *my-var* 2)
(defun my-function-2 ()
*my-var*)
------------------------------------------------------------------------
I'm loading them both and going in package-2.
After this
*my-var* => 2
(compile 'my-function-2)
(my-function-2) => 2
Now
(shadowing-import 'package-1::*my-var*)
And atter that
*my-var* => 1
But
(my-function-2) => 2
I should recompile MY-FUNCTION-2 to see changes. Would you mind to
explain why ?
--
Vladimir Zolotykh
* Vladimir Zolotykh wrote:
> I should recompile MY-FUNCTION-2 to see changes. Would you mind to
> explain why ?
Because the decision about what symbol is meant by some characters in
your source code is made at read time - namely when the source text of
your definition is turned into an object by the function READ[1]. In
particular it's not strictly the case that you need to recompile your
definition to pick up the new string->symbol mapping, you actually
need to reread the source text. Of course if you call COMPILE-FILE,
or invoke the compiler from the editor then the source text actually
is re-read, but it's the re-reading, not the compilation, that is
doing the work[2].
Here's an elaborate example which shows what is happening (this may
not be completely correct as I just typed it in, sorry if so):
--Cut--
;;;;
;;;
(in-package :cl-user)
;;; Make sure that FUN does not exist in CL-USER.
;;; The EVAL-WHENs here & below are to make things happen the same way
;;; if you compile & load the file as if you load the source
;;;
(eval-when (:load-toplevel :compile-toplevel :execute)
(unintern 'fun (find-package :cl-user)))
(defpackage :subpack
(:use)
(:export #:fun))
(eval-when (:load-toplevel :compile-toplevel :execute)
(use-package ':subpack))
(defun fun (x)
;; A definition for the symbol SUBPACK:FUN
(cons 'fun x))
(defparameter *source-text*
;; The source text of a function
"(lambda (x) (fun x))")
(defparameter *subpack-function-source*
;; The source text converted to a list ready to compile.
;; When this happens FUN means SUBPACK:FUN
(read-from-string *source-text*))
(eval-when (:load-toplevel :compile-toplevel :execute)
(unuse-package ':subpack))
(defun fun (x)
;; A definition for the symbol CL-USER::FUN
(cons 'fun x))
(defparameter *not-subpack-function-source*
;; The source text converted to a list ready to compile.
;; When this happens FUN means CL-USER::FUN
(read-from-string *source-text*))
;;; Now look at the two FUNCTION-SOURCE variables - you will see that the
;;; symbol FUN is different - in particular
;;; (eql (car (cdr (cdr *subpack-function-source*)))
;;; (car (cdr (cdr *not-subpack-function-source*)))
;;; is false
(defparameter *sf*
;; Result of calling the first function
(funcall (compile nil *subpack-function-source*) 1))
(defparameter *nsf*
;; Result of calling the second function
(funcall (compile nil *not-subpack-function-source*) 1))
;;; Now look at (car *sf*) and (car *nsf*) - again they are different symbols
;;;
--Cut--
--tim
Footnotes:
[1] Or by some equivalent - I don't think there's a guarantee that the
compiler calls READ itself - it might call some system-internal
function with the same effect.
[2] On the Xerox Lisp Machines, which had a structure editor - DEdit
or (later, and better) SEdit, invoking the compiler from the
editor did *not* re-read the source, and it was actually fairly
tricky to deal with changes in the package structure.
Thank you Tim, Kalle
I hope I understood. To Tim's example (very illustrative I think) I
venture to add some more. Of course they illustrate the same idea:
after reading the symbols are replaced with references to it in
particular package (but probable this sounds rater vaguely).
Uninterning symbol affects only further references to it.
------------------------------------------------------------------------
(defvar *secret* 'secret)
(defun secret () *secret*)
(defun (setf secret) (new)
(setq *secret* new))
(unintern '*secret*)
*secret* => error
(secret *secret*) => secret
------------------------------------------------------------------------
(defclass my-secret ()
((secret :initarg :secret :reader my-secret-get
:writer my-secret-set)))
(setq *secret* (make-instance 'my-secret :secret 'secret))
(unintern 'secret)
(slot-value *secret* 'secret) => error
(my-secret-get *secret*) => secret
------------------------------------------------------------------------
--
Vladimir Zolotykh
Vladimir Zolotykh <······@eurocom.od.ua> writes:
> I should recompile MY-FUNCTION-2 to see changes. Would you mind to
> explain why ?
Compiling the function has no effect on this: you'll get the
same effect even if you don't compile MY-FUNCTION-2 before you
shadowing-import *MY-VAR*. What matters is when the function is
read.
It also doesn't matter that it is a function. For example, you
could do:
(in-package :package-2)
(unintern '*my-var*)
(defvar *my-var* 2)
(defvar *symbol* '*my-var*)
(shadowing-import 'package-1::*my-var*)
Then, the value of *SYMBOL* is #:*MY-VAR*, i.e., the variable
still refers to the old symbol, which is now uninterned.
You can even get the symbol back into the package:
(shadowing-import *symbol*)
This isn't quite enough, though: uninterning PACKAGE-2::*MY-VAR*
has caused it to have no home package, and importing it back
won't change that. Is it at all possible to change the home
package back? I don't see a (SETF SYMBOL-PACKAGE) function.
Also, should such an "apparently uninterned" symbol print as
"#:*MY-VAR*" or "*MY-VAR*" when PACKAGE-2 is the current package?
The description of UNINTERN says "such symbols are always printed
preceded by #:", but GNU CLISP 2.26 printed just "*MY-VAR*".
* Kalle Olavi Niemitalo wrote:
> Also, should such an "apparently uninterned" symbol print as
> "#:*MY-VAR*" or "*MY-VAR*" when PACKAGE-2 is the current package?
> The description of UNINTERN says "such symbols are always printed
> preceded by #:", but GNU CLISP 2.26 printed just "*MY-VAR*".
This depends on *print-escape* and *print-gensym* (and indirectly on
*print-readably*).
--tim