From: Christophe Rhodes
Subject: Re: Blowfish, and a question about DEFCONSTANT
Date: 
Message-ID: <sqptbsg9jc.fsf@lambda.dyndns.org>
Alain Picard <············@memetrics.com> writes:

> Many thanks to Christopher Rhodes for patches which
                 ^^^^^^^^^^^
Oh well :-/

> I have a question, however, either about the behaviour
> of DEFCONSTANT, or that of SBCL.

Let's start with the chapter and verse:

   [...] 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.
     -- from the "Macro DEFCONSTANT" page in CLHS

The "same value" here implies that successive evaluations should be
EQL to each other.  So SBCL is complaining here about 'uninterned
structured constants' such as arrays, where successive evaluations of
will not preserve EQLity.

As for why this is: well, it comes down to the equality and copying
operations again: there is no one-size-fits-all "generic" copier or
equality tester, so there is no right answer (other than object
identity) for comparing constants with each other.  In addition, there
are very real issues when compiling multiple files with such a
structured constant definition in play; each fasl will end up with a
/different/ (non-eql) constant value substituted for references to the
constant.

Why do LispWorks and CMUCL let this through, then?  Well, as in your
case, some uses of structured constants aren't for the constant
itself, but the constant's members, using (defconstant +a+ '(1 2 3))
as conceptual shorthand for 
  (defconstant +(car a)+ 1)
  (defconstant +(cadr a)+ 2)
  (defconstant +(caddr a)+ 3)
CMUCL and LispWorks presumably let this through either by having no
tests at all for constant redefinition, or (more likely) by having
heuristic tests for guessing when this situation is likely, and
relaxing the test to one such as EQUAL (for lists) or STRING=/EQUALP
(for strings).

In your case this is particularly acute, because access to the tables
in the blowfish algorithm really does need to be constant-folded away
for performance reasons.  The first thing, and possibly the easiest
from your point of view, would be to adapt your defconstant forms to
  (defconstant +foo+
    (if (boundp '+foo+)
        +foo+
        (make-array ...)))
to ensure that the value form does always evaluate to the same (EQL)
value.  This I think[*] will give you the behaviour you expect, at a
slight cost in column-inches.  If you view SBCL's rather strict
interpretation of the rules as a bondage-and-discipline thing, though,
you may wish simply to specify that sbcl users must compile and load
blowfish wrapped in 
  (handler-bind ((sb-ext:defconstant-uneql #'abort))
    ...)
to handle the conditions automatically.  This could be automated with
an asdf system for blowfish (which comes highly recommended anyway so
that users can download and compile it automatically).  Two other
possible "workarounds" are to define your own defconstantish macro
with its own particular equality check, and to replace defconstants by
defparameters; neither of these latter ones is terribly useful in the
case of your blowfish implementation.

Christophe

[*] I'm not sure.  I think it's possible to imagine an implementation
of a compile-time environment where this doesn't do quite the right
thing.  My guess is that it's OK in practice.
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)

From: Frode Vatvedt Fjeld
Subject: Re: Blowfish, and a question about DEFCONSTANT
Date: 
Message-ID: <2hznawhmxk.fsf@vserver.cs.uit.no>
Christophe Rhodes <·····@cam.ac.uk> writes:

> [..] As for why this is: well, it comes down to the equality and
> copying operations again: there is no one-size-fits-all "generic"
> copier or equality tester, so there is no right answer (other than
> object identity) for comparing constants with each other.  In
> addition, there are very real issues when compiling multiple files
> with such a structured constant definition in play; each fasl will
> end up with a /different/ (non-eql) constant value substituted for
> references to the constant.

I have discussed this previously with Christophe, but I thought I'd
re-iterate my perspective on this here.

This issue (also) comes down to whether defconstant is (1) a promise
by the user to the compiler/lisp system (approximately "this variable
will almost never be changed, so please inline references to it
whenever you find appropriate"), or (2) from the compiler to the user
("references to this variable will always return /the same/ value").

One might find support for (2) in the standard's wording, but
personally I find this interpretation to remove a great deal of the
usefulness of defconstant: Firstly under (2) one will have to consider
for each use of defconstant whether this has to be changed to
e.g. defparameter, based on whether the value is eql-readable or not,
or perhaps quit using defconstant altogether. Secondly, inlining
compund values can have great potential for performance benefits in
some situations, and under (2) there is no longer any natural way to
express this.

-- 
Frode Vatvedt Fjeld
From: Nikodemus Siivola
Subject: Re: Blowfish, and a question about DEFCONSTANT
Date: 
Message-ID: <633d72b.0403050206.2635fc37@posting.google.com>
Christophe Rhodes <·····@cam.ac.uk> wrote in message news:<··············@lambda.dyndns.org>...

> possible "workarounds" are to define your own defconstantish macro
> with its own particular equality check, and to replace defconstants by
> defparameters; neither of these latter ones is terribly useful in the
> case of your blowfish implementation.

Any reason why this would not be appropriate?

(defmacro defconst (name value &optional doc)
  `(unless (boundp ',name)
      (defconstant ,name ,value ,@(when doc (list doc)))))

Cheers,

 -- Nikodemus Siivola
From: Thomas F. Burdick
Subject: Re: Blowfish, and a question about DEFCONSTANT
Date: 
Message-ID: <xcv4qt27v6c.fsf@famine.OCF.Berkeley.EDU>
·········@random-state.net (Nikodemus Siivola) writes:

> Christophe Rhodes <·····@cam.ac.uk> wrote in message news:<··············@lambda.dyndns.org>...
> 
> > possible "workarounds" are to define your own defconstantish macro
> > with its own particular equality check, and to replace defconstants by
> > defparameters; neither of these latter ones is terribly useful in the
> > case of your blowfish implementation.
> 
> Any reason why this would not be appropriate?
> 
> (defmacro defconst (name value &optional doc)
>   `(unless (boundp ',name)
>       (defconstant ,name ,value ,@(when doc (list doc)))))

Even better:

  (defmacro defconstant-once (name value &optional doc)
    `(defconstant ,name (if (boundp ',name) ,value ,name)
                  ,@(when doc (list doc))))

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Carl Shapiro
Subject: Re: Blowfish, and a question about DEFCONSTANT
Date: 
Message-ID: <ouy8yif3uj2.fsf@panix3.panix.com>
·········@random-state.net (Nikodemus Siivola) writes:

> (defmacro defconst (name value &optional doc)
>   `(unless (boundp ',name)
>       (defconstant ,name ,value ,@(when doc (list doc)))))

FYI, Zetalisp defines a macro called DEFCONST which is different than
the Common Lisp DEFCONSTANT and the output of your macro.  DEFCONST
behaves like the standard Common Lisp DEFPARAMETER.
From: Alexey Dejneka
Subject: Re: Blowfish, and a question about DEFCONSTANT
Date: 
Message-ID: <m3eks78g1s.fsf@comail.ru>
·········@random-state.net (Nikodemus Siivola) writes:

> Any reason why this would not be appropriate?
> 
> (defmacro defconst (name value &optional doc)
>   `(unless (boundp ',name)
>       (defconstant ,name ,value ,@(when doc (list doc)))))

This DEFCONSTANT will not be on top level; its value will be unknown
during compile-time.

-- 
Regards,
Alexey Dejneka

"Alas, the spheres of truth are less transparent than those of
illusion." -- L.E.J. Brouwer
From: Alain Picard
Subject: Re: Blowfish, and a question about DEFCONSTANT
Date: 
Message-ID: <87fzcnd4y0.fsf@memetrics.com>
Christophe Rhodes <·····@cam.ac.uk> writes:

> Alain Picard <············@memetrics.com> writes:
>
>> Many thanks to Christopher Rhodes for patches which
>                  ^^^^^^^^^^^
> Oh well :-/

My most sincere and abject apologies, Christophe.  :-)

>
> Let's start with the chapter and verse:
>
>    [...] An implementation may choose to evaluate the value-form at
>    compile time, load time, or both. Therefore, users must ensure that
 excellent analysis snipped.

Thanks for that.  I guess it makes sense, and I shall change
my code as you suggest, but I feel, as Frode does, that this
makes DEFCONSTANT a lot less useful and intuitive than I'd like
it to be.   Oh well, them's the breaks.