From: Frank GOENNINGER
Subject: Macro mysteries ... please help ...
Date: 
Message-ID: <m2ocu6jqdg.fsf@goenninger.net>
Showing my newbieness again ... But yeah, please help me out of a macro
mystery I'm currently struggling with:

The "error" says:

; While compiling (:TOP-LEVEL-FORM "cello-opengl.lisp" 21239):
Warning: Free reference to undeclared variable
         +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ assumed special.


I have the following code:

(defmacro eval-now! (&body body)
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     ,@body))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defmacro export! (&rest symbols)
    `(eval-when (:compile-toplevel :load-toplevel :execute)
       (export ,@symbols))))

(eval-now!
  (defmacro define-constant (name value &optional docstring)
   "Define a constant properly.  If NAME is unbound, DEFCONSTANT
it to VALUE.  If it is already bound, and it is EQUAL to VALUE,
reuse the SYMBOL-VALUE of NAME.  Otherwise, DEFCONSTANT it again,
resulting in implementation-specific behavior."
   `(defconstant ,name
      (if (not (boundp ',name))
          ,value
          (let ((value ,value))
            (if (equal value (symbol-value ',name))
                (symbol-value ',name)
                value)))
      ,@(when docstring (list docstring)))))

(eval-now!
  (defmacro define-constant! (symbol value)
    `(progn
       (eval-now!
         (define-constant ,symbol ,value)
         (export ',symbol)))))

(defun make-color (name red blue green alpha)
  (make-instance 'color :md-name name 
                 :red red :blue blue :green green :alpha alpha))

(defmacro define-color (name red green blue alpha)
  `(let ((color (make-color ',name ,red ,green ,blue ,alpha)))
     (progn
       (define-constant! ,name color)
       (pushnew color *registered-colors*)
       color)))

The error above is caused by the lines 

(define-color +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ 0 0 0 255) ;; This is ok
(defvar *gl-default-light-ambient-color* +GL-DEFAULT-LIGHT-AMBIENT-COLOR+)

The intention is to have a default color defined but we may define
another value for the var *gl-default-light-ambient-color* over the
constant. Later code then uses only the *gl...* variable ...

WTF is going on here ? I macroexpanded like crazy and still have a
problem of the trees and forrest kind ...

TIA !!!

Best,
   Frank

From: Pillsy
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <6479b61b-1a0f-4aad-9847-dc5e762b0720@s16g2000vbp.googlegroups.com>
On May 6, 9:46 am, Frank GOENNINGER <······@googlemail.com> wrote:
> Showing my newbieness again ... But yeah, please help me out of a macro
> mystery I'm currently struggling with:
[...]
> (defmacro define-color (name red green blue alpha)
>   `(let ((color (make-color ',name ,red ,green ,blue ,alpha)))
>      (progn
>        (define-constant! ,name color)
>        (pushnew color *registered-colors*)
>        color)))

> The error above is caused by the lines

> (define-color +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ 0 0 0 255) ;; This is ok
> (defvar *gl-default-light-ambient-color* +GL-DEFAULT-LIGHT-AMBIENT-COLOR+)

> The intention is to have a default color defined but we may define
> another value for the var *gl-default-light-ambient-color* over the
> constant. Later code then uses only the *gl...* variable ...

I doubt I'm less of a n00b than you. Nonetheless:

DEFINE-COLOR expands into a LET form, which means what is contained
inside is not a toplevel form. Try wrapping it with an EVAL-WHEN form
to make sure it is treated like a toplevel form.

If you don't mind me asking though, I'm a little unclear on why you're
bothering with doing this in the first place. You already are
maintaining a registry of colors which is keyed by color name; why not
just use that directly in DEFINE-COLOR?

Cheers,
Pillsy
From: Kaz Kylheku
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <20090517083205.695@gmail.com>
On 2009-05-06, Frank GOENNINGER <······@googlemail.com> wrote:
> Showing my newbieness again ... But yeah, please help me out of a macro
> mystery I'm currently struggling with:
>
> The "error" says:
>
> ; While compiling (:TOP-LEVEL-FORM "cello-opengl.lisp" 21239):
> Warning: Free reference to undeclared variable
>          +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ assumed special.
>
>
> I have the following code:
>
> (defmacro eval-now! (&body body)
>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>      ,@body))

Bad name; this should be called EVAL-ALWAYS (i.e. in all situations).

> (eval-when (:compile-toplevel :load-toplevel :execute)
>   (defmacro export! (&rest symbols)

Wrapping DEFMACROs in EVAL-WHEN is not required.

>     `(eval-when (:compile-toplevel :load-toplevel :execute)
>        (export ,@symbols))))

The expansion here could just be `(eval-now! (export ,@symbols)).

> (eval-now!

Unnecessary.

>   (defmacro define-constant (name value &optional docstring)
>    "Define a constant properly.  If NAME is unbound, DEFCONSTANT

DEFCONSTANT defines a constant properly.

> it to VALUE.  If it is already bound, and it is EQUAL to VALUE,
> reuse the SYMBOL-VALUE of NAME.  Otherwise, DEFCONSTANT it again,
> resulting in implementation-specific behavior."
>    `(defconstant ,name
>       (if (not (boundp ',name))
>           ,value
>           (let ((value ,value))
>             (if (equal value (symbol-value ',name))
>                 (symbol-value ',name)
>                 value)))
>       ,@(when docstring (list docstring)))))

This is useless, and potentially dangerous. If an attempt is made
to redefine a constant to a different value, this situation is swept under the
rug.

If you just use an unadorned DEFCONSTANT, there is a fighting chance you may
get a diagnostic for that situation.

> (eval-now!
>   (defmacro define-constant! (symbol value)
>     `(progn
>        (eval-now!
>          (define-constant ,symbol ,value)
>          (export ',symbol)))))

Entangling package manipulation with program semantics like this is
probably a bad idea.

> (defun make-color (name red blue green alpha)
>   (make-instance 'color :md-name name 
>                  :red red :blue blue :green green :alpha alpha))
>
> (defmacro define-color (name red green blue alpha)
>   `(let ((color (make-color ',name ,red ,green ,blue ,alpha)))
>      (progn
>        (define-constant! ,name color)
>        (pushnew color *registered-colors*)
>        color)))
>

The LET here is a toplevel form, but the PROGN enclosed in it is not a toplevel
form.  See the CLHS, 3.2.3.1 Processing of Top Level Forms.

A DEFCONSTANT which is not at top level won't be processed properly by the
compiler.

As a side, note that EVAL-WHEN forms which are in non-toplevel forms basically
reduce to the :EXECUTE situation. The :LOAD-TOPLEVEL and :COMPILE-TOPLEVEL
situations are irrelevant. If you don't have :EXECUTE in a non-toplevel
EVAL-WHEN, it basically means ``don't evaluate this, ever''.
From: Frank GOENNINGER
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <m2y6tahyi7.fsf@goenninger.net>
Kaz Kylheku <········@gmail.com> writes:

> On 2009-05-06, Frank GOENNINGER <······@googlemail.com> wrote:
>> Showing my newbieness again ... But yeah, please help me out of a macro
>> mystery I'm currently struggling with:
>>
>> The "error" says:
>>
>> ; While compiling (:TOP-LEVEL-FORM "cello-opengl.lisp" 21239):
>> Warning: Free reference to undeclared variable
>>          +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ assumed special.
>>
>>
>> I have the following code:
>>
>> (defmacro eval-now! (&body body)
>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>>      ,@body))
>
> Bad name; this should be called EVAL-ALWAYS (i.e. in all situations).

Yep. True. Changed it.

>> (eval-when (:compile-toplevel :load-toplevel :execute)
>>   (defmacro export! (&rest symbols)
>
> Wrapping DEFMACROs in EVAL-WHEN is not required.
>
>>     `(eval-when (:compile-toplevel :load-toplevel :execute)
>>        (export ,@symbols))))

Uhm... Ok.

>
> The expansion here could just be `(eval-now! (export ,@symbols)).
>
>> (eval-now!
>
> Unnecessary.
>
>>   (defmacro define-constant (name value &optional docstring)
>>    "Define a constant properly.  If NAME is unbound, DEFCONSTANT
>
> DEFCONSTANT defines a constant properly.

Yes, sort of ;-)

>
>> it to VALUE.  If it is already bound, and it is EQUAL to VALUE,
>> reuse the SYMBOL-VALUE of NAME.  Otherwise, DEFCONSTANT it again,
>> resulting in implementation-specific behavior."
>>    `(defconstant ,name
>>       (if (not (boundp ',name))
>>           ,value
>>           (let ((value ,value))
>>             (if (equal value (symbol-value ',name))
>>                 (symbol-value ',name)
>>                 value)))
>>       ,@(when docstring (list docstring)))))
>
> This is useless, and potentially dangerous. If an attempt is made
> to redefine a constant to a different value, this situation is swept under the
> rug.
>
> If you just use an unadorned DEFCONSTANT, there is a fighting chance you may
> get a diagnostic for that situation.

Yes, yes. I did it on purpose, though. I *do* like Pascal's version with
the continuable error - detects the problem but let's me continue.

>> (eval-now!
>>   (defmacro define-constant! (symbol value)
>>     `(progn
>>        (eval-now!
>>          (define-constant ,symbol ,value)
>>          (export ',symbol)))))
>
> Entangling package manipulation with program semantics like this is
> probably a bad idea.

Maybe I am just not up to it, but: I don't get what you tell me here...

>
>> (defun make-color (name red blue green alpha)
>>   (make-instance 'color :md-name name 
>>                  :red red :blue blue :green green :alpha alpha))
>>
>> (defmacro define-color (name red green blue alpha)
>>   `(let ((color (make-color ',name ,red ,green ,blue ,alpha)))
>>      (progn
>>        (define-constant! ,name color)
>>        (pushnew color *registered-colors*)
>>        color)))
>>
>
> The LET here is a toplevel form, but the PROGN enclosed in it is not a toplevel
> form.  See the CLHS, 3.2.3.1 Processing of Top Level Forms.
>
> A DEFCONSTANT which is not at top level won't be processed properly by the
> compiler.
>
> As a side, note that EVAL-WHEN forms which are in non-toplevel forms basically
> reduce to the :EXECUTE situation. The :LOAD-TOPLEVEL and :COMPILE-TOPLEVEL
> situations are irrelevant. If you don't have :EXECUTE in a non-toplevel
> EVAL-WHEN, it basically means ``don't evaluate this, ever''.

A new one for me , and an important one. Thanks for explaining this, Kaz!

CHeers
   Frank
From: Kenneth Tilton
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <4a01f0c0$0$22526$607ed4bc@cv.net>
> Kaz Kylheku <········@gmail.com> writes:

>>> (defmacro eval-now! (&body body)
>>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>>>      ,@body))
>> Bad name; 

What part of Buddhism do you not understand? All there is is now, and 
now is all times. Any time that will never be now hardly matters.

>> this should be called EVAL-ALWAYS (i.e. in all situations).

No, that would mean it gets dispatched to a background process and loops 
such that it is always running.

hth,kzo
From: ··················@gmail.com
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <a9821875-d783-4a1b-b36c-2a2a4f08fd9b@o27g2000vbd.googlegroups.com>
On May 6, 4:19 pm, Kenneth Tilton <·········@gmail.com> wrote:
> > Kaz Kylheku <········@gmail.com> writes:
> >>> (defmacro eval-now! (&body body)
> >>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
> >>>      ,@body))
> >> Bad name;
>
> What part of Buddhism do you not understand? All there is is now, and
> now is all times. Any time that will never be now hardly matters.
>
> >> this should be called EVAL-ALWAYS (i.e. in all situations).
>
> No, that would mean it gets dispatched to a background process and loops
> such that it is always running.
>
> hth,kzo

Now is always; eval-always is the same as eval-now.

Lets call it 'eval-when-top'.
From: Kenneth Tilton
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <4a01fc03$0$5909$607ed4bc@cv.net>
··················@gmail.com wrote:
> On May 6, 4:19 pm, Kenneth Tilton <·········@gmail.com> wrote:
>>> Kaz Kylheku <········@gmail.com> writes:
>>>>> (defmacro eval-now! (&body body)
>>>>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>>>>>      ,@body))
>>>> Bad name;
>> What part of Buddhism do you not understand? All there is is now, and
>> now is all times. Any time that will never be now hardly matters.
>>
>>>> this should be called EVAL-ALWAYS (i.e. in all situations).
>> No, that would mean it gets dispatched to a background process and loops
>> such that it is always running.
>>
>> hth,kzo
> 
> Now is always; eval-always is the same as eval-now.

Now is all times, not always.

hth, kzo
From: Kaz Kylheku
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <20090517150553.201@gmail.com>
On 2009-05-06, Kenneth Tilton <·········@gmail.com> wrote:
> ··················@gmail.com wrote:
>> On May 6, 4:19 pm, Kenneth Tilton <·········@gmail.com> wrote:
>>>> Kaz Kylheku <········@gmail.com> writes:
>>>>>> (defmacro eval-now! (&body body)
>>>>>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>>>>>>      ,@body))
>>>>> Bad name;
>>> What part of Buddhism do you not understand? All there is is now, and
>>> now is all times. Any time that will never be now hardly matters.
>>>
>>>>> this should be called EVAL-ALWAYS (i.e. in all situations).
>>> No, that would mean it gets dispatched to a background process and loops
>>> such that it is always running.
>>>
>>> hth,kzo
>> 
>> Now is always; eval-always is the same as eval-now.
>
> Now is all times, not always.

But it's always now. :)
From: Kenneth Tilton
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <4a020ab1$0$5400$607ed4bc@cv.net>
Kaz Kylheku wrote:
> On 2009-05-06, Kenneth Tilton <·········@gmail.com> wrote:
>> ··················@gmail.com wrote:
>>> On May 6, 4:19 pm, Kenneth Tilton <·········@gmail.com> wrote:
>>>>> Kaz Kylheku <········@gmail.com> writes:
>>>>>>> (defmacro eval-now! (&body body)
>>>>>>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>>>>>>>      ,@body))
>>>>>> Bad name;
>>>> What part of Buddhism do you not understand? All there is is now, and
>>>> now is all times. Any time that will never be now hardly matters.
>>>>
>>>>>> this should be called EVAL-ALWAYS (i.e. in all situations).
>>>> No, that would mean it gets dispatched to a background process and loops
>>>> such that it is always running.
>>>>
>>>> hth,kzo
>>> Now is always; eval-always is the same as eval-now.
>> Now is all times, not always.
> 
> But it's always now. :)

Glad to see this list back on track. Meanwhile, what's up with the damn 
rose girl and volcano sweeping? Apparently I will be explaining this for 
the rest of my life.

kt
From: namekuseijin
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <609321a6-b0a2-4069-aa92-36407866ce40@z19g2000vbz.googlegroups.com>
On May 6, 7:10 pm, Kenneth Tilton <·········@gmail.com> wrote:
> Kaz Kylheku wrote:
> > On 2009-05-06, Kenneth Tilton <·········@gmail.com> wrote:
> >> ··················@gmail.com wrote:
> >>> On May 6, 4:19 pm, Kenneth Tilton <·········@gmail.com> wrote:
> >>>>> Kaz Kylheku <········@gmail.com> writes:
> >>>>>>> (defmacro eval-now! (&body body)
> >>>>>>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
> >>>>>>>      ,@body))
> >>>>>> Bad name;
> >>>> What part of Buddhism do you not understand? All there is is now, and
> >>>> now is all times. Any time that will never be now hardly matters.
>
> >>>>>> this should be called EVAL-ALWAYS (i.e. in all situations).
> >>>> No, that would mean it gets dispatched to a background process and loops
> >>>> such that it is always running.
>
> >>>> hth,kzo
> >>> Now is always; eval-always is the same as eval-now.
> >> Now is all times, not always.
>
> > But it's always now. :)
>
> Glad to see this list back on track. Meanwhile, what's up with the damn
> rose girl and volcano sweeping? Apparently I will be explaining this for
> the rest of my life.

well, you should, cause now I'm curious.  And I mean always now! :D
From: ··················@gmail.com
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <d4061204-ba19-4014-bd4b-0acf2e6927c7@e20g2000vbc.googlegroups.com>
On May 6, 5:07 pm, Kenneth Tilton <·········@gmail.com> wrote:
> ··················@gmail.com wrote:
> > On May 6, 4:19 pm, Kenneth Tilton <·········@gmail.com> wrote:
> >>> Kaz Kylheku <········@gmail.com> writes:
> >>>>> (defmacro eval-now! (&body body)
> >>>>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
> >>>>>      ,@body))
> >>>> Bad name;
> >> What part of Buddhism do you not understand? All there is is now, and
> >> now is all times. Any time that will never be now hardly matters.
>
> >>>> this should be called EVAL-ALWAYS (i.e. in all situations).
> >> No, that would mean it gets dispatched to a background process and loops
> >> such that it is always running.
>
> >> hth,kzo
>
> > Now is always; eval-always is the same as eval-now.
>
> Now is all times, not always.
>
> hth, kzo

Are you sure it is 'all times' and not 'any time'?
Now is any time.

'All times' implied to me a rejection of traditional linear thinking
about the concept of time.

i.e. Time is an arbitrary (psychological/metaphysical) construct based
on the relation of objects in space. Meaning that our belief that
things around us are happening 'sequentially' is merely an abstraction
which we impose on the world to help make sense of it.

Saying 'now is all times' would imply to me then that all times are
happening same time, and that any time is 'now', and that always is
also 'now' (as all 'nows' are happening at the same time).

But you know, its probably the fever.
From: Kenneth Tilton
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <4a027463$0$5377$607ed4bc@cv.net>
··················@gmail.com wrote:
> On May 6, 5:07 pm, Kenneth Tilton <·········@gmail.com> wrote:
>> ··················@gmail.com wrote:
>>> On May 6, 4:19 pm, Kenneth Tilton <·········@gmail.com> wrote:
>>>>> Kaz Kylheku <········@gmail.com> writes:
>>>>>>> (defmacro eval-now! (&body body)
>>>>>>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>>>>>>>      ,@body))
>>>>>> Bad name;
>>>> What part of Buddhism do you not understand? All there is is now, and
>>>> now is all times. Any time that will never be now hardly matters.
>>>>>> this should be called EVAL-ALWAYS (i.e. in all situations).
>>>> No, that would mean it gets dispatched to a background process and loops
>>>> such that it is always running.
>>>> hth,kzo
>>> Now is always; eval-always is the same as eval-now.
>> Now is all times, not always.
>>
>> hth, kzo
> 
> Are you sure it is 'all times' and not 'any time'?

I said 'all times'.

> Now is any time.

Hmmm. Is that even /grammatically/ meaningful?

> 
> 'All times' implied to me a rejection of traditional linear thinking
> about the concept of time.

Not to quibble, but it is not linearity that is under attack by the 
Buddhist, rather the idea that there are even enough things to line up. 
Only now exists -- the past is past, the future has not come. Can't line 
up one thing outside a koan. Time's illusions, however, are free to line up.

> 
> i.e. Time is an arbitrary (psychological/metaphysical) construct based
> on the relation of objects in space. Meaning that our belief that
> things around us are happening 'sequentially' is merely an abstraction
> which we impose on the world to help make sense of it.

Physicists. <spit> They say causation can run backwards because their 
equations involving time have no direction. Muhammad Ali would approve 
their hubris.

Worse, what physicists dismisses as a special case is precisely the 
scale at which the most complex entities in the universe (people) have 
meaning. We're all simply shattered by the slow aging of neutrinos but 
if you don't mind I'm in the middle of a game of darts...

They do, however, have the coolest toy in the world, and I wish them 
luck in finding the Higgs Boson. If they do I am flying to Cern, I bet 
those guys are going to party like it's 1999.

> 
> Saying 'now is all times' would imply to me then that all times are
> happening same time, and that any time is 'now', and that always is
> also 'now' (as all 'nows' are happening at the same time).
> 
> But you know, its probably the fever.

Damn. I thought for a moment someone was taking me seriously.

kt
From: George Neuner
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <qj16059dg2ejqh755p46fdptfc9h1pdnmv@4ax.com>
On Thu, 07 May 2009 01:41:00 -0400, Kenneth Tilton
<·········@gmail.com> wrote:

>··················@gmail.com wrote:
>
>> Now is any time.
>
>Hmmm. Is that even /grammatically/ meaningful?

The grammar is technically correct ... whether it has meaning is
another question entirely.

Grammar, being only about language structure, is theoretically
independent of meaning.

George
From: Rob Warnock
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <Y_ednR3CPK7lOp7XnZ2dnUVZ_q6dnZ2d@speakeasy.net>
Kaz Kylheku  <········@gmail.com> wrote:
+---------------
| Frank GOENNINGER <······@googlemail.com> wrote:
| > I have the following code:
| > (defmacro eval-now! (&body body)
| >   `(eval-when (:compile-toplevel :load-toplevel :execute)
| >      ,@body))
| 
| Bad name; this should be called EVAL-ALWAYS (i.e. in all situations).
+---------------

Heh. Mine got called simply EVAL-WHEN* by analogy to shell wildcarding. ;-}

[...not to mention the general CL convention of adding a "*" suffix
to indicate local tweaks of standard forms.]

+---------------
| >   (defmacro define-constant (name value &optional docstring)
| >    "Define a constant properly.  If NAME is unbound, DEFCONSTANT
| 
| DEFCONSTANT defines a constant properly.
+---------------

And its "constant" status must be made available to the user
at compile time:

    Macro DEFCONSTANT
    ...
    If a defconstant form appears as a top level form, the
    compiler must recognize that name names a constant variable.
    ...

and:

    Function CONSTANTP
    ... symbols declared as constant by the user in the indicated
    environment using DEFCONSTANT are always considered constant forms
    and must be recognized as such by CONSTANTP.

*BUT*... The compiler does *not* necessarily bind a constant variable
to a *value* at compile time. Again from "Macro DEFCONSTANT":
   
    An implementation may choose to evaluate the value-form at
    compile time, load time, or both.

If the compiler chooses load-time only [e.g., as CMUCL does],
then the new constant variable will be "constant but unbound"
in subsequent macro expansions. For example:

    (defconstant +foo+ 1234)

    (defmacro dbgv (&rest forms)
      `(eval-when (:compile-toplevel :load-toplevel :execute)
	,@(loop for form in forms collect
	  `(format t "DBGV: ~s = ~s~%" ',form ,form))))

    (dbgv (constantp '+foo+)
	  (boundp '+foo+)
	  (when (boundp '+foo+) +foo+))  

If you COMPILE-FILE the above with CMUCL, you'll get:

    cmu> (compile-file "foo.lisp")

    ; Python version 1.1, VM version Intel x86 on 06 MAY 09 05:56:20 pm.
    ; Compiling: /u/rpw3/foo.lisp 06 MAY 09 05:56:10 pm

    DBGV: (CONSTANTP (QUOTE +FOO+)) = T
    DBGV: (BOUNDP (QUOTE +FOO+)) = NIL
    DBGV: (WHEN (BOUNDP (QUOTE +FOO+)) +FOO+) = NIL
    ; Byte Compiling Top-Level Form:

    ; foo.x86f written.
    ; Compilation finished in 0:00:00.
    #P"/u/rpw3/foo.x86f"
    NIL
    NIL
    cmu> 

This is perfectly legal, but means that CONSTANTP cannot portably or
reliably be used to tell whether a value is available at compile time,
even if it is known to be "constant". Therefore macros that depend upon
CONSTANTP for that information [instead of BOUNDP] are non-portable.

Note that "the right thing" happens at load time, of course:

    cmu> (load *)

    ; Loading #P"/u/rpw3/foo.x86f".
    DBGV: (CONSTANTP (QUOTE +FOO+)) = T
    DBGV: (BOUNDP (QUOTE +FOO+)) = T
    DBGV: (WHEN (BOUNDP (QUOTE +FOO+)) +FOO+) = 1234
    T
    cmu> 

Finally, another "gotcha" with DEFCONSTANT is implementations
which choose the "both" choice in the above text, repeated here:

    An implementation may choose to evaluate the value-form at
    compile time, load time, or both.

because of the very next sentence:

    Therefore, users must ensure that the initial-value can be evaluated
    at compile time (regardless of whether or not references to name
    appear in the file) and that it always evaluates to the same value.

Therefore macros that depend on DEFCONSTANT to evaluate the value-form
only at load-time are *also* non-portable. You have been warned!  ;-}


-Rob

p.s. The above mild rant is the result of some problems I had once
with a new version of HTOUT. Turned out that Tim Bradshaw and I were
using CL implementations that did different things with DEFCONSTANT
value-forms. [The current version of HTOUT has a fix for that.]

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal J. Bourguignon
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <7cab5q5mxw.fsf@pbourguignon.anevia.com>
Frank GOENNINGER <······@googlemail.com> writes:

> (eval-now!
>   (defmacro define-constant (name value &optional docstring)
>    "Define a constant properly.  If NAME is unbound, DEFCONSTANT
> it to VALUE.  If it is already bound, and it is EQUAL to VALUE,
> reuse the SYMBOL-VALUE of NAME.  Otherwise, DEFCONSTANT it again,
> resulting in implementation-specific behavior."
>    `(defconstant ,name
>       (if (not (boundp ',name))
>           ,value
>           (let ((value ,value))
>             (if (equal value (symbol-value ',name))
>                 (symbol-value ',name)
>                 value)))
>       ,@(when docstring (list docstring)))))
>
> (define-color +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ 0 0 0 255) ;; This is ok
> (defvar *gl-default-light-ambient-color* +GL-DEFAULT-LIGHT-AMBIENT-COLOR+)
>
> The intention is to have a default color defined but we may define
> another value for the var *gl-default-light-ambient-color* over the
> constant. Later code then uses only the *gl...* variable ...
>
> WTF is going on here ? I macroexpanded like crazy and still have a
> problem of the trees and forrest kind ...

Try this:

(eval-now!
 (defmacro define-constant (name value &optional docstring)
   "Define a constant properly.  If NAME is unbound, DEFCONSTANT
 it to VALUE.  If it is already bound, and it is EQUAL to VALUE,
 reuse the SYMBOL-VALUE of NAME.  Otherwise, DEFCONSTANT it again,
 resulting in implementation-specific behavior."
   (let ((vvalue (gensym)))
     `(let ((,vvalue ,value))
        (cond
          ((not (boundp ',name))
           ;; A new constant
           (defconstant ,name (load-time-value ,value t)
             ,@(when docstring (list docstring))))
          ((equal ,name ,vvalue)
           ;; already defined with the same value, we don't try to change it.
           ,@ (when docstring
                `((when (and (documentation ',name 'constant)
                             (string/= ',docstring (documentation ',name 'constant)))
                    (setf  (documentation ',name 'constant) ',docstring))))
           ',name)
          (t
           ;; changing the value of a constant!
           (cerror "Redefine all the same."
                   "Redefining the constant ~S = ~S with a different vvalue ~S"
                   ',name ,name ,vvalue)
           (defconstant ,name (load-time-value ,value t)
             ,@(when docstring (list docstring)))))))))

-- 
__Pascal Bourguignon__
From: Frank GOENNINGER
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <m2k54ujfbd.fsf@goenninger.net>
···@informatimago.com (Pascal J. Bourguignon) writes:

> Try this:
>
> (eval-now!
>  (defmacro define-constant (name value &optional docstring)
>    "Define a constant properly.  If NAME is unbound, DEFCONSTANT
>  it to VALUE.  If it is already bound, and it is EQUAL to VALUE,
>  reuse the SYMBOL-VALUE of NAME.  Otherwise, DEFCONSTANT it again,
>  resulting in implementation-specific behavior."
>    (let ((vvalue (gensym)))
>      `(let ((,vvalue ,value))
>         (cond
>           ((not (boundp ',name))
>            ;; A new constant
>            (defconstant ,name (load-time-value ,value t)
>              ,@(when docstring (list docstring))))
>           ((equal ,name ,vvalue)
>            ;; already defined with the same value, we don't try to change it.
>            ,@ (when docstring
>                 `((when (and (documentation ',name 'constant)
>                              (string/= ',docstring (documentation ',name 'constant)))
>                     (setf  (documentation ',name 'constant) ',docstring))))
>            ',name)
>           (t
>            ;; changing the value of a constant!
>            (cerror "Redefine all the same."
>                    "Redefining the constant ~S = ~S with a different vvalue ~S"
>                    ',name ,name ,vvalue)
>            (defconstant ,name (load-time-value ,value t)
>              ,@(when docstring (list docstring)))))))))

Merci, Pascal!

It does provide the more wider problem of �correctly� defining a
constant. However, it did not solve my original problem ;-)

I'm still trying ...

Cheers and thanks again!

  Frank
From: Kaz Kylheku
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <20090517120624.199@gmail.com>
On 2009-05-06, Frank GOENNINGER <······@googlemail.com> wrote:
> ···@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Try this:
>>
>> (eval-now!
>>  (defmacro define-constant (name value &optional docstring)
>>    "Define a constant properly.  If NAME is unbound, DEFCONSTANT
>>  it to VALUE.  If it is already bound, and it is EQUAL to VALUE,
>>  reuse the SYMBOL-VALUE of NAME.  Otherwise, DEFCONSTANT it again,
>>  resulting in implementation-specific behavior."
>>    (let ((vvalue (gensym)))
>>      `(let ((,vvalue ,value))
>>         (cond
>>           ((not (boundp ',name))
>>            ;; A new constant
>>            (defconstant ,name (load-time-value ,value t)
>>              ,@(when docstring (list docstring))))
>>           ((equal ,name ,vvalue)
>>            ;; already defined with the same value, we don't try to change it.
>>            ,@ (when docstring
>>                 `((when (and (documentation ',name 'constant)
>>                              (string/= ',docstring (documentation ',name 'constant)))
>>                     (setf  (documentation ',name 'constant) ',docstring))))
>>            ',name)
>>           (t
>>            ;; changing the value of a constant!
>>            (cerror "Redefine all the same."
>>                    "Redefining the constant ~S = ~S with a different vvalue ~S"
>>                    ',name ,name ,vvalue)
>>            (defconstant ,name (load-time-value ,value t)
>>              ,@(when docstring (list docstring)))))))))
>
> Merci, Pascal!
>
> It does provide the more wider problem of «correctly» defining a
> constant. 

That is nonsense. The standard Common Lisp macro DEFCONSTANT solves the problem
of defining a constant.  Correctly is a matter of conforming to some
preconceptions.  Maybe you mean ``robust'' rather than ``correct'', which means
conforming to some preconceptions about gracefully handling situations that
correspond to what is considered bad input.  

DEFCONSTANT, as defined in the language, is embroiled in a number of potential
undefined behaviors. Its definitionn in the ANSI Sspec is not robust.

A macro like the above does not solve all of the issues, though.

Moreover, implementations can, and do, provide a DEFCONSTANT, and
surrounding behaviors, which are hardened against the situations which are
marked as undefined behavior.

The job of signaling an error if a constant is badly redefined belongs inside
DEFCONSTANT; it's a quality-of-implementation issue.

One undefined behavior occurs if a constant is defined in the situation that
the symbol already has a binding. This allows Lisp compilers to treat the
symbol as a pervasive constant which takes precedence over any other bindings.

The BOUNDP check in the above macro is inadequate to catch all  these
situations, because there are bindings, even global ones, which don't show up
as BOUNDP.

  (define-symbol-macro foo 42)
 
  (boundp 'foo) -> NIL

  (defconstant foo 43)  ;; undefined behavior.

  foo -> ??? ;; 42 or 43? Or error signal? 
             ;; Different answer whether compiled or interpreted?

Another problem with the macro is that it might not do the right job
at compile time, which is when you need it to do that.
See, suppose that in a compilation unit you have:
 
  (defvar foo 42) ;; this /is/ a BOUNDP binding

  (define-constant foo 43)

The define-constant will expand to some form which tries to evaluate the BOUNDP
at compile time. But the problem is that FOO isn't bound at compile time,
because the DEFVAR is compiled, not evaluated.

Try putting this into a file and compiling it:

  (defvar foo 42)

  (eval-when (:compile-toplevel) (print (boundp 'foo)))

I get a NIL output during compilation. The variable FOO is not actually defined
inside the Lisp image that is running the compiler.

To implement a DEFCONSTANT that is totally robust, you need
implementation-specific hooks which can peer into the compiler's data
structures. You need to ask the question, ``Did we previously compile some form
which binds this symbol?'' not ``Did we bind this symbol?''.

One more though to chew on is that if it was so trivially easy to make a
totally robust DEFCONSTANT in portable Lisp, maybe the seasoned Lisp
hackers who came up with Common Lisp would have specified a totally
robust DEFCONSTANT without those undefined behaviors.
From: Pascal J. Bourguignon
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <87ws8t3opn.fsf@galatea.local>
Kaz Kylheku <········@gmail.com> writes:

> On 2009-05-06, Frank GOENNINGER <······@googlemail.com> wrote:
>> ···@informatimago.com (Pascal J. Bourguignon) writes:
>>
>>> Try this:
>>>
>>> (eval-now!
>>>  (defmacro define-constant (name value &optional docstring)
>> [...]
>> It does provide the more wider problem of �correctly� defining a
>> constant. 
>
> That is nonsense. The standard Common Lisp macro DEFCONSTANT solves the problem
> of defining a constant. 

I definitely agree.  In particular this sentence of clhs defconstant:

    The consequences are undefined if there are any bindings of the
    variable named by name at the time  defconstant is executed or if
    the value is not eql to the value of initial-value.

let me conclude that DEFCONSTANT should be used only on symbols,
characters and numbers, and should be avoided for any other data
type.   I use DEFPARAMETER for them.


Constants aren't, variables won't.
-- 
__Pascal Bourguignon__
From: Madhu
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <m3zldqs1sm.fsf@moon.robolove.meer.net>
* Frank GOENNINGER <··············@goenninger.net> :
Wrote on Wed, 06 May 2009 15:46:35 +0200:

|
| (defmacro define-color (name red green blue alpha)
|   `(let ((color (make-color ',name ,red ,green ,blue ,alpha)))
|      (progn
|        (define-constant! ,name color)
|        (pushnew color *registered-colors*)
|        color)))
|
| The error above is caused by the lines 
|
| (define-color +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ 0 0 0 255) ;; This is ok
| (defvar *gl-default-light-ambient-color* +GL-DEFAULT-LIGHT-AMBIENT-COLOR+)
|

Long story short: For this to work like you expect, DEFINE-COLOR should
expand to a Top-Level EVAL-WHEN form. The LET destroys top-levelness of
the progn.  You could use 

(defmacro define-color (name red green blue alpha)
  `(eval-now!
    (let ((color (make-color ',name ,red ,green ,blue ,alpha)))
      (progn
	(define-constant! ,name color)
	(pushnew color *registered-colors*)
	color))))

or you need to (eval-when (...) (define-color XXX )) before using it in
a DEFVAR.

Now, you seem to have had more success with Cello than I did.  Last
time, I tried, I got as far as getting IX-TOGL to render text in a
simple example.  But IX-TEXT only renders bitmap and outline fonts:
texture fonts do not get rendered.  Also the rendered text went
successively off the screen to the right after a few redisplays...

If you do have some working code, would it be possible to share it? Can
I use your me.com address to send my questions?

--
Madhu
From: Frank GOENNINGER
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <m24ovyjdtt.fsf@goenninger.net>
Madhu <·······@meer.net> writes:

> Long story short: For this to work like you expect, DEFINE-COLOR should
> expand to a Top-Level EVAL-WHEN form. The LET destroys top-levelness of
> the progn.  You could use 
>
> (defmacro define-color (name red green blue alpha)
>   `(eval-now!
>     (let ((color (make-color ',name ,red ,green ,blue ,alpha)))
>       (progn
> 	(define-constant! ,name color)
> 	(pushnew color *registered-colors*)
> 	color))))
>
> or you need to (eval-when (...) (define-color XXX )) before using it in
> a DEFVAR.

Yep. And it *does* work now ;-) Thanks to you and Pillsy!
>
> Now, you seem to have had more success with Cello than I did.  Last
> time, I tried, I got as far as getting IX-TOGL to render text in a
> simple example.  But IX-TEXT only renders bitmap and outline fonts:
> texture fonts do not get rendered.  Also the rendered text went
> successively off the screen to the right after a few redisplays...

Hehe. Cello had (and still has, IMHO) some rough edges, for sure. That
drove me to a quite rude approach: Re-write stuff in some places, take
the real good stuff over to what I call �Cello NX�. Kenny knows about
this effort and he is not untroubled with me asking questions... By now
I can safely say I have read, debugged, or re-written about 90% of Cello
to make Cello NX come true.

> If you do have some working code, would it be possible to share it?

Sure. As 90% of it is Cello the new Cello NX inherits Cello's license -
which is LLGPL.

> Can I use your me.com address to send my questions?

Of course! Shoot ...

>
> --
> Madhu

Cheers,
   Frank
From: Pascal Costanza
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <76fgq8F1cabv2U1@mid.individual.net>
Frank GOENNINGER wrote:
> Showing my newbieness again ... But yeah, please help me out of a macro
> mystery I'm currently struggling with:
> 
> The "error" says:
> 
> ; While compiling (:TOP-LEVEL-FORM "cello-opengl.lisp" 21239):
> Warning: Free reference to undeclared variable
>          +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ assumed special.
> 
> 
> I have the following code:
> 
> (defmacro eval-now! (&body body)
>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>      ,@body))
> 
> (eval-when (:compile-toplevel :load-toplevel :execute)
>   (defmacro export! (&rest symbols)
>     `(eval-when (:compile-toplevel :load-toplevel :execute)
>        (export ,@symbols))))
> 
> (eval-now!
>   (defmacro define-constant (name value &optional docstring)
>    "Define a constant properly.
[...]

Constants are overrated. Try to solve a real problem. ;)



Pascal

-- 
ELS'09: http://www.european-lisp-symposium.org/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Frank GOENNINGER
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <m23abh5l7g.fsf@goenninger.net>
Pascal Costanza <··@p-cos.net> writes:

> Frank GOENNINGER wrote:
>> Showing my newbieness again ... But yeah, please help me out of a macro
>> mystery I'm currently struggling with:
>>
>> The "error" says:
>>
>> ; While compiling (:TOP-LEVEL-FORM "cello-opengl.lisp" 21239):
>> Warning: Free reference to undeclared variable
>>          +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ assumed special.
>>
>>
>> I have the following code:
>>
>> (defmacro eval-now! (&body body)
>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>>      ,@body))
>>
>> (eval-when (:compile-toplevel :load-toplevel :execute)
>>   (defmacro export! (&rest symbols)
>>     `(eval-when (:compile-toplevel :load-toplevel :execute)
>>        (export ,@symbols))))
>>
>> (eval-now!
>>   (defmacro define-constant (name value &optional docstring)
>>    "Define a constant properly.
> [...]
>
> Constants are overrated. Try to solve a real problem. ;)
>
>
>
> Pascal

Hehe. Yep. With all that fuzz about constants they are now gone from my
code... A normal defparameters does the job, too. I still put '+-es
around the names, though ...

Frank
From: Pascal Costanza
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <76fqmbF1cabe3U1@mid.individual.net>
Frank GOENNINGER wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>> Frank GOENNINGER wrote:
>>> Showing my newbieness again ... But yeah, please help me out of a macro
>>> mystery I'm currently struggling with:
>>>
>>> The "error" says:
>>>
>>> ; While compiling (:TOP-LEVEL-FORM "cello-opengl.lisp" 21239):
>>> Warning: Free reference to undeclared variable
>>>          +GL-DEFAULT-LIGHT-AMBIENT-COLOR+ assumed special.
>>>
>>>
>>> I have the following code:
>>>
>>> (defmacro eval-now! (&body body)
>>>   `(eval-when (:compile-toplevel :load-toplevel :execute)
>>>      ,@body))
>>>
>>> (eval-when (:compile-toplevel :load-toplevel :execute)
>>>   (defmacro export! (&rest symbols)
>>>     `(eval-when (:compile-toplevel :load-toplevel :execute)
>>>        (export ,@symbols))))
>>>
>>> (eval-now!
>>>   (defmacro define-constant (name value &optional docstring)
>>>    "Define a constant properly.
>> [...]
>>
>> Constants are overrated. Try to solve a real problem. ;)
>>
>>
>>
>> Pascal
> 
> Hehe. Yep. With all that fuzz about constants they are now gone from my
> code... A normal defparameters does the job, too. I still put '+-es
> around the names, though ...

Exactly. defparameter and defvar are sufficient, I think. There are only 
few 'real' constants (like pi). Everything else is premature optimization.

Furthermore, I think define-symbol-macro could be used as a neat 
replacement for constants, with the added advantage that you can 
actually reuse the variable name with local binding constructs.

And remember Alan Perlis: "One man's constant is another man's variable."

See http://www.cs.yale.edu/quotes.html ;)


Pascal

-- 
ELS'09: http://www.european-lisp-symposium.org/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Madhu
Subject: Re: Macro mysteries ... please help ...
Date: 
Message-ID: <m3zldp19xu.fsf@moon.robolove.meer.net>
* Pascal Costanza <···············@mid.individual.net> :
Wrote on Thu, 07 May 2009 12:15:39 +0200:

[re defconstant]

| Exactly. defparameter and defvar are sufficient, I think. There are
| only few 'real' constants (like pi). Everything else is premature
| optimization.
|
| Furthermore, I think define-symbol-macro could be used as a neat
| replacement for constants, with the added advantage that you can
| actually reuse the variable name with local binding constructs.
|
| And remember Alan Perlis: "One man's constant is another man's
| variable."

--
The primary purpose of the DATA statement is to give names to constants;
instead of referring to pi as 3.141592653589793 at every appearance, the
variable PI can be given that value with a DATA statement and used
instead of the longer form of the constant.  This also simplifies
modifying the program, should the value of pi change.
	-- FORTRAN manual for Xerox Computers
%