From: Christophe R. <cs...@ca...> - 2013-06-03 21:15:26
|
Alex McGuire <ca...@gm...> writes: > The following code > > (defstruct foo x) > (defconstant +bar+ (make-foo :x 1)) > > > fails to compile with the error > > * (compile-file "foo") > > ; compiling file "/home/alex/repos/cribbage/foo.lisp" (written 02 JUN 2013 > 12:58:12 AM): > ; compiling (DEFSTRUCT FOO ...) > ; compiling (DEFCONSTANT +BAR+ ...) > debugger invoked on a UNDEFINED-FUNCTION in thread > #<THREAD "main thread" RUNNING {1002A38F13}>: > The function COMMON-LISP-USER::MAKE-FOO is undefined. > > sbcl 1.1.7 running on 64 bit ubuntu Right, because defconstant must (in portable code) be able to evaluate its value form at compile-time, but there's no guarantee that defstruct has the compile-time side-effect of making constructor functions available. So your code can't be compiled in SBCL because SBCL uses the freedom afforded to it to implement defstruct and defconstant in a particular way. > For what it's worth the same code compile successfully under clisp. No > error occurs if defconstant is replaced with defparameter. For defparameter, there is no such need for the value form to be evaluated at compile-time; all that must happen at compile-time is that the symbol be declared special, so that later references to it are compiled as dynamic variable lookups. The evaluation of the value form (and the establishment of the binding) happens when the compiled code is loaded. Even if you arranged to have the constructor function available at compile-time, for example by doing (eval-when (:compile-toplevel :load-toplevel :execute) (defstruct foo x)) (defconstant +bar+ (make-foo :x 1)) the code would still not be portable, because another constraint is that the value form of defconstant must be the same (under EQL) whenever the form is evaluated, in this case both at compile-time and at load-time -- but MAKE-FOO will return a fresh, non-EQL structure. You could use initialization forms that check whether +BAR+ already has a value, but usually it is not a good idea to have structured data bound as a constant in any case. You could use defparameter, as you've discovered, or defglobal if there is a reason to disallow rebinding. Best wishes, Christophe |