From: Steven E. Harris
Subject: defconstant/compile-file interaction
Date: 
Message-ID: <jk4sm2n1qpa.fsf@W003275.na.alarismed.com>
Say I have the following two forms in a file:


(defun some-func (n)
  (1+ n))

(defconstant +magic+
  (some-func 41))


The intent is to define a constant with a value of some potentially
expensive computation. These definitions work fine until I try to feed
this file to the compiler.

Using Allegro CL 7, it complains:

,----
| attempt to call `SOME-FUNC' which is an undefined function.
|    [Condition of type UNDEFINED-FUNCTION]
`----

CLISP compiled the file without complaint.

Reading the HyperSpec on defconstant, I found this paragraph:

,----[ CLHS: defconstant ]
| If a defconstant form appears as a top level form, the compiler must
| recognize that name names a constant variable. An implementation may
| choose to evaluate the value-form at compile time, load time, or
| both. 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.
`----

I tried sprinkling some eval-when fairy dust, which did the trick for
Allegro:


(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun some-func (n)
    (1+ n)))

(defconstant +magic+
  (some-func 41))


Is adding the eval-when operator the right solution here, or is there
some other technique should I be using instead?

-- 
Steven E. Harris

From: Thomas A. Russ
Subject: Re: defconstant/compile-file interaction
Date: 
Message-ID: <ymism2nxwf8.fsf@sevak.isi.edu>
"Steven E. Harris" <ยทยทยท@panix.com> writes:

> 
> Using Allegro CL 7, it complains:
> 
> ,----
> | attempt to call `SOME-FUNC' which is an undefined function.
> |    [Condition of type UNDEFINED-FUNCTION]
> `----
> 
> CLISP compiled the file without complaint.
> 
> Reading the HyperSpec on defconstant, I found this paragraph:
> 
> ,----[ CLHS: defconstant ]
> | If a defconstant form appears as a top level form, the compiler must
> | recognize that name names a constant variable. An implementation may
> | choose to evaluate the value-form at compile time, load time, or
> | both. 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.
> `----
> 
> I tried sprinkling some eval-when fairy dust, which did the trick for
> Allegro:
> 
> 
> (eval-when (:compile-toplevel :load-toplevel :execute)
>   (defun some-func (n)
>     (1+ n)))
> 
> (defconstant +magic+
>   (some-func 41))
> 
> 
> Is adding the eval-when operator the right solution here, or is there
> some other technique should I be using instead?

It is precisely the correct solution here.

As you were able to work out from the error message and the information
in the HyperSpec, implementations can choose exactly when to evaluate
the form for the defconstant.  As you discovered CLISP and ACL took
advantage of that freedom to choose different evaluation times.

But since the specification allows implementations to evaluate the value
form at compile time, it follows that the value must be computable at
compile time.  Among other things, that requires that any functions used
in the computation of the value need to be available in the compile time
environment, which is exactly what the EVAL-WHEN clause arranges.  The
inclusion of :compile-toplevel is what makes SOME-FUNC available in the
compile time environment.  That, in turn, allows evaluation of the
constant at that time.  This capability is needed to allow constant
folding optimizations to take place.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Costanza
Subject: Re: defconstant/compile-file interaction
Date: 
Message-ID: <3ab81aF69m56nU1@individual.net>
Steven E. Harris wrote:
> Say I have the following two forms in a file:
> 
> 
> (defun some-func (n)
>   (1+ n))
> 
> (defconstant +magic+
>   (some-func 41))
> 
> 
> The intent is to define a constant with a value of some potentially
> expensive computation. These definitions work fine until I try to feed
> this file to the compiler.

I also had some fights against defconstant in the past, and I think 
there are some solutions out there to make some things work better, but 
I think by now that it's probably not worth the fuzz. Remember the rule 
that you shouldn't optimize your program without a benchmark that tells 
you that you're dealing with an actual bottleneck of your program.

Just use defvar or defparameter.


Pascal

P.S.: Other tools in Common Lisp to get around issues with defconstant 
are #. (read-time evaluation), load-time-value and symbol-macros.