From: David Steuber
Subject: SHADOW, EXPORT And DEFMACRO
Date: 
Message-ID: <874qgei1h4.fsf@david-steuber.com>
I am having problems with some Lisp code that I am generating with a
program that processes the output of ffigen 3.4.1 on OS X.  I am using
OpenMCL, but I think this is a case where I am not quite understanding
ANSI behavior.

The following listing is hand written code that I have in pacakge
"GLM".  My generated code expects it to work.

;--- Begin Listing ---
(in-package "GLM")

(defun shadow-symbol (sym)
  (multiple-value-bind (s i) (find-symbol (string sym))
    (when (and i (eq i :inherited))
      (shadow s))))

(defmacro define-type (name type)
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     (glm::shadow-symbol ',name)
     (uffi:def-foreign-type ,name ,type)
     (uffi:def-type ,name ,type)
     (export ',name)
     ',name))

(defmacro def-constant (name value)
  `(uffi:def-constant ,name ,value :export t))

(defun def-function-aux (arglist)
  (if (null (car arglist))
      '(())
      `(,arglist)))

(defmacro def-function (names return &rest args)
  (let ((sym (cadr names)))
    `(eval-when (:compile-toplevel :load-toplevel :execute)
       (glm::shadow-symbol ',sym)
       (uffi:def-function ,names ,@(def-function-aux args) :returning ,return)
       (export ',sym)
       ',sym)))

;--- End Listing ---

Forms that cause problems when doing compile and load file or just
loading a fasl (in-package "GL"):

(glm::define-type byte                signed-char)

=> Complains that byte must be imported before it can be exported.

I had hoped that glm::define-type would have shadowed cl:byte first.

(glm::def-function ("glRotatef" rotatef) void
  (arg1 gl::float)
  (arg2 gl::float)
  (arg3 gl::float)
  (arg4 gl::float))

=> Complains about redefining macro cl:rotatef as a function.

I had hoped that glm::def-function would have shadowed cl:rotatef
first.

None of the glm::def-constant forms have any issues.

Oddly enough, both of the above forms will compile if I do C-c C-c on
them in SLIME (compile form).  Once I've done that, C-c C-k works.  Of
course the fasl will not load later (in a future lisp session).  I get
the complaint about byte.  The other big problem is that these issues
prevent a fresh batch compile of my system from working.

I have the package that gl:byte and gl:rotatef are defined in declared
in another file like this:

  (defpackage :cl-opengl
    (:documentation
     "The package for CL-OpenGL")
    (:nicknames :gl)
    (:use common-lisp))

I've got nearly 5000 lines of generated code that do not generate any
complaints from OpenMCL.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1

From: Barry Margolin
Subject: Re: SHADOW, EXPORT And DEFMACRO
Date: 
Message-ID: <barmar-A3C59D.08473415022005@comcast.dca.giganews.com>
In article <··············@david-steuber.com>,
 David Steuber <·····@david-steuber.com> wrote:

> I am having problems with some Lisp code that I am generating with a
> program that processes the output of ffigen 3.4.1 on OS X.  I am using
> OpenMCL, but I think this is a case where I am not quite understanding
> ANSI behavior.
> 
> The following listing is hand written code that I have in pacakge
> "GLM".  My generated code expects it to work.
> 
> ;--- Begin Listing ---
> (in-package "GLM")
> 
> (defun shadow-symbol (sym)
>   (multiple-value-bind (s i) (find-symbol (string sym))
>     (when (and i (eq i :inherited))
>       (shadow s))))
> 
> (defmacro define-type (name type)
>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>      (glm::shadow-symbol ',name)

Since you're already in the GLM package, you don't need to qualify 
SHADOW-SYMBOL.

>      (uffi:def-foreign-type ,name ,type)
>      (uffi:def-type ,name ,type)
>      (export ',name)
>      ',name))
> 
> (defmacro def-constant (name value)
>   `(uffi:def-constant ,name ,value :export t))
> 
> (defun def-function-aux (arglist)
>   (if (null (car arglist))
>       '(())
>       `(,arglist)))
> 
> (defmacro def-function (names return &rest args)
>   (let ((sym (cadr names)))
>     `(eval-when (:compile-toplevel :load-toplevel :execute)
>        (glm::shadow-symbol ',sym)
>        (uffi:def-function ,names ,@(def-function-aux args) :returning ,return)
>        (export ',sym)
>        ',sym)))
> 
> ;--- End Listing ---
> 
> Forms that cause problems when doing compile and load file or just
> loading a fasl (in-package "GL"):
> 
> (glm::define-type byte                signed-char)
> 
> => Complains that byte must be imported before it can be exported.
> 
> I had hoped that glm::define-type would have shadowed cl:byte first.
> 
> (glm::def-function ("glRotatef" rotatef) void
>   (arg1 gl::float)
>   (arg2 gl::float)
>   (arg3 gl::float)
>   (arg4 gl::float))
> 
> => Complains about redefining macro cl:rotatef as a function.
> 
> I had hoped that glm::def-function would have shadowed cl:rotatef
> first.

It did.  But you didn't define the function on the shadowed symbol, you 
defined it on the symbol that was originally read.  You need to call 
INTERN to get the new symbol:

(uffi:def-function (,(first names) ,(intern (symbol-name (second names)))
                    ,@(cddr names)) ...)

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: David Steuber
Subject: Re: SHADOW, EXPORT And DEFMACRO
Date: 
Message-ID: <87ll9pa3f3.fsf@david-steuber.com>
Barry Margolin <······@alum.mit.edu> writes:

> In article <··············@david-steuber.com>,
>  David Steuber <·····@david-steuber.com> wrote:
> 
> > (defmacro define-type (name type)
> >   `(eval-when (:compile-toplevel :load-toplevel :execute)
> >      (glm::shadow-symbol ',name)
> 
> Since you're already in the GLM package, you don't need to qualify 
> SHADOW-SYMBOL.

Which is the home package for symbols that appear in a macro
definition?  Will the symbols always get a package qualifier when the
macro is expanded in a different package?

> > I had hoped that glm::def-function would have shadowed cl:rotatef
> > first.
> 
> It did.  But you didn't define the function on the shadowed symbol, you 
> defined it on the symbol that was originally read.  You need to call 
> INTERN to get the new symbol:
> 
> (uffi:def-function (,(first names) ,(intern (symbol-name (second names)))
>                     ,@(cddr names)) ...)

Ok.  I tried using intern and also list as Marco suggested.  I was
still having troubles though:

(defmacro define-type (name type)
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     (shadow-symbol ',name)
     (uffi:def-foreign-type ,(intern (symbol-name name)) ,type)
     (uffi:def-type ,(intern (symbol-name name)) ,type)
     (export (intern (symbol-name ',name)))
     ',name))

After this, I stopped getting errors from define-type.  It seems a bit
busy though.  And:

(defmacro def-function (names return &rest args)
  (let ((str (car names))
        (sym (cadr names)))
    `(eval-when (:compile-toplevel :load-toplevel :execute)
       (shadow-symbol ',sym)
       (intern (symbol-name ',sym))
       (uffi:def-function ,(list str (intern (symbol-name sym)))
  ,@(def-function-aux args) :returning ,return)
       (export ',sym)
       ',sym)))

Def-function was still giving me trouble.  Again it's gotten rather
busy.  I finally decided to yank common-lisp out of my :use:

  (defpackage :cl-opengl
    (:documentation
     "The package for CL-OpenGL")
    (:nicknames :gl)
    (:use ))

This finally got compiling and loading to work on the first go, but it
doesn't really address my original issue.  Then I found this in the
CLHS on make-package:

    In situations where the packages to be used contain symbols which
    would conflict, it is necessary to first create the package with
    :use '(), then to use shadow or shadowing-import to address the
    conflicts, and then after that to use use-package once the
    conflicts have been addressed.

This implies that you can't use a package until after the name
conflicts have been dealt with by shadowing.  Does this mean that
defpackage handles :shadow before :use?

I guess I still have some confusion over the whole package and macro
interaction.

Thanks.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Barry Margolin
Subject: Re: SHADOW, EXPORT And DEFMACRO
Date: 
Message-ID: <barmar-4DFBC2.00051116022005@comcast.dca.giganews.com>
In article <··············@david-steuber.com>,
 David Steuber <·····@david-steuber.com> wrote:

> Barry Margolin <······@alum.mit.edu> writes:
> 
> > In article <··············@david-steuber.com>,
> >  David Steuber <·····@david-steuber.com> wrote:
> > 
> > > (defmacro define-type (name type)
> > >   `(eval-when (:compile-toplevel :load-toplevel :execute)
> > >      (glm::shadow-symbol ',name)
> > 
> > Since you're already in the GLM package, you don't need to qualify 
> > SHADOW-SYMBOL.
> 
> Which is the home package for symbols that appear in a macro
> definition?  Will the symbols always get a package qualifier when the
> macro is expanded in a different package?

Interning happens at *read* time, not expansion time (except when the 
macro itself calls INTERN).

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Marco Antoniotti
Subject: Re: SHADOW, EXPORT And DEFMACRO
Date: 
Message-ID: <IjpQd.14$fp1.42973@typhoon.nyu.edu>
David Steuber wrote:
> Forms that cause problems when doing compile and load file or just
> loading a fasl (in-package "GL"):
> 
> (glm::define-type byte                signed-char)
> 
> => Complains that byte must be imported before it can be exported.
> 
> I had hoped that glm::define-type would have shadowed cl:byte first.
> 
> (glm::def-function ("glRotatef" rotatef) void
>   (arg1 gl::float)
>   (arg2 gl::float)
>   (arg3 gl::float)
>   (arg4 gl::float))
> 
> => Complains about redefining macro cl:rotatef as a function.
> 
> I had hoped that glm::def-function would have shadowed cl:rotatef
> first.

The problem is that the form above is "read" by the reader first and 
then macro expanded.  At read time the "ROTATEF" symbol is not shadowed 
yet.  You are shadowing SYM within GLM::DEF-FUNCTION, but then you are 
calling UFFI:DEF-FUNCTION with ,NAMES which contains the reference to 
cl:rotatef. Hence the mishap.

Try to change the call to UFFI:DEF-FUNCTION to

	(uffi:def-function ,(list (first names) sym) ...)

I think that would do it.

Cheers
--
Marco











> 
> None of the glm::def-constant forms have any issues.
> 
> Oddly enough, both of the above forms will compile if I do C-c C-c on
> them in SLIME (compile form).  Once I've done that, C-c C-k works.  Of
> course the fasl will not load later (in a future lisp session).  I get
> the complaint about byte.  The other big problem is that these issues
> prevent a fresh batch compile of my system from working.
> 
> I have the package that gl:byte and gl:rotatef are defined in declared
> in another file like this:
> 
>   (defpackage :cl-opengl
>     (:documentation
>      "The package for CL-OpenGL")
>     (:nicknames :gl)
>     (:use common-lisp))
> 
> I've got nearly 5000 lines of generated code that do not generate any
> complaints from OpenMCL.
> 
From: Kent M Pitman
Subject: Re: SHADOW, EXPORT And DEFMACRO
Date: 
Message-ID: <u4qgbshnq.fsf@nhplace.com>
David Steuber <·····@david-steuber.com> writes:

> (defmacro define-type (name type)
>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>      (glm::shadow-symbol ',name)
>      (uffi:def-foreign-type ,name ,type)
>      (uffi:def-type ,name ,type)
>      (export ',name)
>      ',name))

A Good rule of Thumb:  "Do not do this."

Ok, in some longer form:

I quite strongly recommend not doing 'demand shadowing'.
There are several problems with this.

First, it's easy to confuse yourself.  You want the print environment to be
the same when you read as when you write.  Since you're planning to write
the above expansion for READing before the shadowing, but you're PRINTing
it after you do the shadow in the other thing, your package state is not the
same and normal claims of print/read invertibility do not apply.

But, philosophically, packages should be stable.  Clients need that.
When you make a package so that it dynamically changes at the drop of a hat,
you're just asking to make trouble for all the clients of the package.
People will compile things expecting a certain set of symbols to be present
and no others.  When you change things and distribute a new package with
different symbols, all hell will break loose.

If your defense is that you ARE stable and are not changing things much, 
you're just defeating any argument against a separate DEFPACKAGE with that
known list of symbols.

I don't really care if the defpackage is generated automatically, or
if you have to do two passes in order to get changes to subside.  But
the package definition should be read first, before any symbol
manipulation is done in the package.  That's not a requirement of the
spec.  It's just typically a practical requirement of people's sanity.
From: David Steuber
Subject: Re: SHADOW, EXPORT And DEFMACRO
Date: 
Message-ID: <87fyzuhk4x.fsf@david-steuber.com>
Kent M Pitman <······@nhplace.com> writes:

> A Good rule of Thumb:  "Do not do this."
> 
> Ok, in some longer form:
> 
> I quite strongly recommend not doing 'demand shadowing'.
> There are several problems with this.
[snipage]
> I don't really care if the defpackage is generated automatically, or
> if you have to do two passes in order to get changes to subside.  But
> the package definition should be read first, before any symbol
> manipulation is done in the package.  That's not a requirement of the
> spec.  It's just typically a practical requirement of people's sanity.

Thanks for the advice, Kent.  I'll fix my code to follow it.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1