From: Vladimir Zolotykh
Subject: symbols and compilation
Date: 
Message-ID: <3C7501CF.FDF495BC@eurocom.od.ua>
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

From: Tim Bradshaw
Subject: Re: symbols and compilation
Date: 
Message-ID: <ey3vgcqvkh2.fsf@cley.com>
* 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.
From: Vladimir Zolotykh
Subject: Re: symbols and compilation
Date: 
Message-ID: <3C762937.B176EDCE@eurocom.od.ua>
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
From: Kalle Olavi Niemitalo
Subject: Re: symbols and compilation
Date: 
Message-ID: <iznit8qlqpf.fsf@stekt34.oulu.fi>
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*".
From: Tim Bradshaw
Subject: Re: symbols and compilation
Date: 
Message-ID: <ey3r8nevk46.fsf@cley.com>
* 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