[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Interpretation of shadowing [and type of argument to SHADOW]



re: ... The SHADOW function always adds the symbol
    to the PACKAGE-SHADOWING-SYMBOLS list, and the informal wording
    on p.186 of CLtL should not be interpreted otherwise.

At Lucid (against our better instincts!) we followed the "letter of the 
law" on page 186.  That phraseology is certainly misguided, but not exactly 
ambiguous:
   "If <condition A is true>, then nothing is done.
    Otherwise,  <step B is taken>.  [And]... also <step C is taken>."
I say, "not ambiguous" because the sentence
    "[And]... also <step C is taken>"
only parses in the context of "something having been done", so that
<step C> is done ALSO, or "in addition" to that "something".

However, that behaviour -- even if mandated by CLtL -- is not productive,
and I would very much like to see it redefined.

On the other hand, this glitch hasn't been the source of the most serious
problem with SHADOW.  The fact that it's argument is a symbol, which it
immediately discards after extracting the symbol-name, has caused a very
subtle bug in virtually every implementation's compiled-code format.  To 
avoid this bug, I would like to see SHADOW changed to take strings as 
arguments, rather than symbols.  More realistically, it should at least be 
permitted to take strings as well as symbols so that one can avoid the 
lossage evident in the following example.

Consider the file:

    (in-package "FOO")
    (shadow 'bar)		   ;maybe this BAR is inherited from LISP?
    (print (symbol-package 'bar))  ;but this BAR should be only in FOO.

How will the call to shadow be compiled when BAR is already present in FOO
as an internal shadowing symbol?  Now consider how that compiled file will 
load into a runtime environment whose package structure is DIFFERENT from 
that of the compile-time environment in the critical aspect that BAR is not 
present in the FOO package (much less being present as a shadowing symbol).
Admittedly, CLtL give the user no guarantees if he doesn't arrange to have 
his runtime package environment "the same" as the compile time one; but this 
scenario is a very common, forgivable one.  It will happen if you compile a 
file twice (from the same Lisp image), and then load the result into a fresh
Lisp image.

At least one Common Lisp implementation has it's compiler recognize
top-level calls to shadow and compile them specially.  But this is
a fix only for the specific situation of top-level calls, not for a
call like:

    (in-package "FOO)
    (funcall (if (probably-true) 
                 #'shadow 
                 #'print)
             'bar)                  ;maybe this BAR is inherited from LISP?
    (print (symbol-package 'bar))   ;but this BAR should be only in FOO.

A much better solution would be to allow the author of this code to write:

    (in-package "FOO)
    (funcall (if (probably-true) 
                 #'shadow 
                 #'print)
             "BAR")                 ;No question about this "BAR" !
    (print (symbol-package 'bar))   ;and this BAR should be only in FOO.

instead.
               

-- JonL --


P.S. Please, no discussion on why  (if (probably-true)  #'shadow  #'print))
     is a useless line of code.  I picked it only to illustrate that this
     particular SHADOW problem isn't completely solved by having the 
     compiler statically re-write the user's code.