From: Ron Garret
Subject: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-2ECFDA.13393721062009@news.albasani.net>
Consider the following code:

(eval-when (:load-toplevel :compile-toplevel :execute)

  (defconstant foo ...)

  (defun foo () foo)

)

Are there any circumstances under which, in an ANSI-compliant 
implementation of CL, (equal foo (foo)) can return NIL?

It turns out that there are.  I'll describe what those circumstances are 
in a moment (makes a good exercise to figure it out on your own).  The 
question I want to raise is, given that this is the case, is this aspect 
of DEFCONSTANT's behavior so at odds with intuition that it can be 
considered broken?  And if so, what, if anything, should be done about 
it?

The circumstnaces under which (equal foo (foo)) can return NIL are the 
following:

1.  FOO is initialized by a non-idempotent initialization function like 
GENSYM or GET-INTERNAL-REAL-TIME.

2.  The code is compiled into a fasl file.

The reason this can lead to (equal foo (foo)) being NIL is that the spec 
says:

"An implementation may choose to evaluate the value-form at compile 
time, load time, OR BOTH." [Emphasis added.]

There is at least one popular implementation of CL (Clozure) that 
actually takes advantage of this latitude and manifests the behavior I 
describe.  SBCL and CLisp apparently don't take advantage of it; they 
both return T to (equal foo (foo)).  I don't have a copy of Allegro or 
Lispworks.

The "problem" (I put it in scare quotes because I consider it a problem 
but reasonable people could disagree -- opening that discussion is the 
point of posting this) is that "constant" can mean two different things:

1.  A value that the user is not allowed to change.

2.  A value that the compiler can assume (but is not obligated to 
assume) won't change, but which might nonetheless actually change.

The ANSI spec implicitly uses definition 2.  IMHO there is more utility 
in definition 1.

Discuss.

rg

From: Kenneth Tilton
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <4a3efadf$0$22537$607ed4bc@cv.net>
Ron Garret wrote:
> Consider the following code:
> 
> (eval-when (:load-toplevel :compile-toplevel :execute)
> 
>   (defconstant foo ...)
> 
>   (defun foo () foo)
> 
> )
> 
> Are there any circumstances under which, in an ANSI-compliant 
> implementation of CL, (equal foo (foo)) can return NIL?
> 
> It turns out that there are.  I'll describe what those circumstances are 
> in a moment (makes a good exercise to figure it out on your own).  The 
> question I want to raise is, given that this is the case, is this aspect 
> of DEFCONSTANT's behavior so at odds with intuition that it can be 
> considered broken?

This is exciting. The massive CLHS for which Schemers like to mock us 
can now be reduced to "Common Lisp: please consult your intuition".

Let's see them top that.

kt
From: Pascal J. Bourguignon
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <87r5xd45oq.fsf@galatea.local>
Ron Garret <·········@flownet.com> writes:

> Consider the following code:
>
> (eval-when (:load-toplevel :compile-toplevel :execute)
>
>   (defconstant foo ...)
>
>   (defun foo () foo)
>
> )
>
> Are there any circumstances under which, in an ANSI-compliant 
> implementation of CL, (equal foo (foo)) can return NIL?

Indeed, but not in conforming code.

    A constant defined by defconstant can be redefined with
    defconstant. However, the consequences are undefined if an attempt
    [...]
    to assign it to a different value using a subsequent defconstant.


> It turns out that there are.  I'll describe what those circumstances are 
> in a moment (makes a good exercise to figure it out on your own).  The 
> question I want to raise is, given that this is the case, is this aspect 
> of DEFCONSTANT's behavior so at odds with intuition that it can be 
> considered broken?  And if so, what, if anything, should be done about 
> it?

Yes, in a way we may consider defconstant to be broken.  What can be
done, is avoid using it.



> The circumstnaces under which (equal foo (foo)) can return NIL are the 
> following:
>
> 1.  FOO is initialized by a non-idempotent initialization function like 
> GENSYM or GET-INTERNAL-REAL-TIME.
>
> 2.  The code is compiled into a fasl file.
>
> The reason this can lead to (equal foo (foo)) being NIL is that the spec 
> says:
>
> "An implementation may choose to evaluate the value-form at compile 
> time, load time, OR BOTH." [Emphasis added.]

That's the reason why YOU, the writer of the defconstant form ARE
RESPONSIBLE to ENSURE that both values are EQL.


    The consequences are undefined if [...]
    the value is not eql to the value of initial-value. 

In the above example, YOU are the BAD GUY who didn't ensure that
defconstant gets twice the same EQL value.  It's all YOUR FAULT.



> There is at least one popular implementation of CL (Clozure) that 
> actually takes advantage of this latitude and manifests the behavior I 
> describe.  SBCL and CLisp apparently don't take advantage of it; they 
> both return T to (equal foo (foo)).  I don't have a copy of Allegro or 
> Lispworks.
>
> The "problem" (I put it in scare quotes because I consider it a problem 
> but reasonable people could disagree -- opening that discussion is the 
> point of posting this) is that "constant" can mean two different things:
>
> 1.  A value that the user is not allowed to change.
>
> 2.  A value that the compiler can assume (but is not obligated to 
> assume) won't change, but which might nonetheless actually change.

But which shouldn't change, if you want defined behavior.

> The ANSI spec implicitly uses definition 2.  IMHO there is more utility 
> in definition 1.

The main problem is that run-time can be merged with load-time,
compilation-time, macroexpansion-time and read-time.  With a lesser
language, such as C, you can easily modify a constant, since then you
have to recompile the program and reload and run it again.  But since
we can do that in a single image, we can only say that behavior will
be defined only when there is a single EQL value.



That said, if you want the value be computed only once, then you can
use LOAD-TIME-VALUE to have it evaluated only at that time:

-------------------(/tmp/a.lisp)-------------------------------
(defconstant +x+ (load-time-value (print (gensym))))
---------------------------------------------------------------


C/USER[8]> (compile-file "/tmp/a.lisp")
;; Compiling file /tmp/a.lisp ...
;; Wrote file /tmp/a.fas
0 errors, 0 warnings
#P"/private/tmp/a.fas" ;
NIL ;
NIL
C/USER[9]> (load "/tmp/a.fas")
;; Loading file /tmp/a.fas ...
#:G10912 
;; Loaded file /tmp/a.fas
T
C/USER[10]> 


-- 
__Pascal Bourguignon__
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-3AA46E.15414921062009@news.albasani.net>
In article <··············@galatea.local>,
 ···@informatimago.com (Pascal J. Bourguignon) wrote:

> Ron Garret <·········@flownet.com> writes:
> 
> > Consider the following code:
> >
> > (eval-when (:load-toplevel :compile-toplevel :execute)
> >
> >   (defconstant foo ...)
> >
> >   (defun foo () foo)
> >
> > )
> >
> > Are there any circumstances under which, in an ANSI-compliant 
> > implementation of CL, (equal foo (foo)) can return NIL?
> 
> Indeed, but not in conforming code.
> 
>     A constant defined by defconstant can be redefined with
>     defconstant. However, the consequences are undefined if an attempt
>     [...]
>     to assign it to a different value using a subsequent defconstant.

That's true.  But there are legitimate use-cases where this is quite 
difficult for the user to achieve.  The particular use-case I'm thinking 
of (the one that brought this issue to my attention) is creating a 
guardian, that is, a singleton that is used as a distinguished value to 
indicate some kind of exceptional condition.  The way I was taught to do 
that is with a gensym, but as you can see that can lead to difficulties.


> > It turns out that there are.  I'll describe what those circumstances are 
> > in a moment (makes a good exercise to figure it out on your own).  The 
> > question I want to raise is, given that this is the case, is this aspect 
> > of DEFCONSTANT's behavior so at odds with intuition that it can be 
> > considered broken?  And if so, what, if anything, should be done about 
> > it?
> 
> Yes, in a way we may consider defconstant to be broken.  What can be
> done, is avoid using it.

Would that be what you recommend?

> > The circumstnaces under which (equal foo (foo)) can return NIL are the 
> > following:
> >
> > 1.  FOO is initialized by a non-idempotent initialization function like 
> > GENSYM or GET-INTERNAL-REAL-TIME.
> >
> > 2.  The code is compiled into a fasl file.
> >
> > The reason this can lead to (equal foo (foo)) being NIL is that the spec 
> > says:
> >
> > "An implementation may choose to evaluate the value-form at compile 
> > time, load time, OR BOTH." [Emphasis added.]
> 
> That's the reason why YOU, the writer of the defconstant form ARE
> RESPONSIBLE to ENSURE that both values are EQL.
> 
> 
>     The consequences are undefined if [...]
>     the value is not eql to the value of initial-value. 
> 
> In the above example, YOU are the BAD GUY who didn't ensure that
> defconstant gets twice the same EQL value.  It's all YOUR FAULT.

I don't dispute that.  What I'm asking is whether the imposition of this 
burden on the programmer should be considered a problem with the 
language design.

> > The ANSI spec implicitly uses definition 2.  IMHO there is more utility 
> > in definition 1.
> 
> The main problem is that run-time can be merged with load-time,
> compilation-time, macroexpansion-time and read-time.

This is a problem?  I thought it was supposed to be a feature.

> With a lesser
> language, such as C, you can easily modify a constant, since then you
> have to recompile the program and reload and run it again.  But since
> we can do that in a single image, we can only say that behavior will
> be defined only when there is a single EQL value.

Well, no, there is another possibility: one could change the spec for 
DEFCONSTANT to say that the initialization form may only be evaluated 
once in any given Lisp image.

> That said, if you want the value be computed only once, then you can
> use LOAD-TIME-VALUE to have it evaluated only at that time:
> 
> -------------------(/tmp/a.lisp)-------------------------------
> (defconstant +x+ (load-time-value (print (gensym))))
> ---------------------------------------------------------------
> 
> 
> C/USER[8]> (compile-file "/tmp/a.lisp")
> ;; Compiling file /tmp/a.lisp ...
> ;; Wrote file /tmp/a.fas
> 0 errors, 0 warnings
> #P"/private/tmp/a.fas" ;
> NIL ;
> NIL
> C/USER[9]> (load "/tmp/a.fas")
> ;; Loading file /tmp/a.fas ...
> #:G10912 
> ;; Loaded file /tmp/a.fas
> T
> C/USER[10]>

I presume you're using CLisp, which already does the Right Thing with 
defconstant even without the use of LOAD-TIME-VALUE.  Using 
LOAD-TIME-VALUE does not solve the problem in CCL.  In fact, using 
LOAD-TIME-VALUE makes the problem worse.  It is not even necessary to 
re-load the fasl file in order to get two different values of FOO.  
Merely compiling the file is enough:

[···@mickey:~]$ cat test.lisp
(eval-when (:compile-toplevel :load-toplevel :execute)

(defconstant foo (load-time-value (get-internal-real-time)))

(defun foo () foo)
)
[···@mickey:~]$ ccl -n
Welcome to Clozure Common Lisp Version 1.4-dev-r12255M-trunk  
(DarwinX8664)!
? (compile-file "test.lisp")
#P"/Users/ron/test.dx64fsl"
NIL
NIL
? (eq foo (foo))
NIL


Is this conclusive evidence of a bug in CCL?

rg
From: Pascal J. Bourguignon
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <87iqip3zzo.fsf@galatea.local>
Ron Garret <·········@flownet.com> writes:

> In article <··············@galatea.local>,
>  ···@informatimago.com (Pascal J. Bourguignon) wrote:
>
>> Ron Garret <·········@flownet.com> writes:
>> 
>> > Consider the following code:
>> >
>> > (eval-when (:load-toplevel :compile-toplevel :execute)
>> >
>> >   (defconstant foo ...)
>> >
>> >   (defun foo () foo)
>> >
>> > )
>> >
>> > Are there any circumstances under which, in an ANSI-compliant 
>> > implementation of CL, (equal foo (foo)) can return NIL?
>> 
>> Indeed, but not in conforming code.
>> 
>>     A constant defined by defconstant can be redefined with
>>     defconstant. However, the consequences are undefined if an attempt
>>     [...]
>>     to assign it to a different value using a subsequent defconstant.
>
> That's true.  But there are legitimate use-cases where this is quite 
> difficult for the user to achieve.  The particular use-case I'm thinking 
> of (the one that brought this issue to my attention) is creating a 
> guardian, that is, a singleton that is used as a distinguished value to 
> indicate some kind of exceptional condition.  The way I was taught to do 
> that is with a gensym, but as you can see that can lead to difficulties.

There should be no difficulty, as long as you don't try to compare the
values that should be EQL but are not, across different times.  And
you would have to do some special things to do so.  For example:

    (defconstant +x+ (gensym))

    (defun f (x)
      (case x
        ((#.+x+) :fails-across-compile/load)))


Anyways, the advice is to use defconstant only on values of type
number, character or (interned) symbol.



>> > It turns out that there are.  I'll describe what those circumstances are 
>> > in a moment (makes a good exercise to figure it out on your own).  The 
>> > question I want to raise is, given that this is the case, is this aspect 
>> > of DEFCONSTANT's behavior so at odds with intuition that it can be 
>> > considered broken?  And if so, what, if anything, should be done about 
>> > it?
>> 
>> Yes, in a way we may consider defconstant to be broken.  What can be
>> done, is avoid using it.
>
> Would that be what you recommend?

Avoid using DEFCONSTANT.  Try DEFPARAMETER, it works better.  But again, 

    (defparameter *x* (gensym))

    (defun f (x)
      (case x
        ((#.*x*) :fails-across-compile/load)))

will fail all the same.


> I don't dispute that.  What I'm asking is whether the imposition of this 
> burden on the programmer should be considered a problem with the 
> language design.

There are a number of features in CL that you would better do without,
indeed.  You may forget about DEFCONSTANT, about logical pathnames,
and a few others....


>> > The ANSI spec implicitly uses definition 2.  IMHO there is more utility 
>> > in definition 1.
>> 
>> The main problem is that run-time can be merged with load-time,
>> compilation-time, macroexpansion-time and read-time.
>
> This is a problem?  I thought it was supposed to be a feature.

It's a problem when you want to define "constants"...



>> With a lesser
>> language, such as C, you can easily modify a constant, since then you
>> have to recompile the program and reload and run it again.  But since
>> we can do that in a single image, we can only say that behavior will
>> be defined only when there is a single EQL value.
>
> Well, no, there is another possibility: one could change the spec for 
> DEFCONSTANT to say that the initialization form may only be evaluated 
> once in any given Lisp image.

This wouldn't prevent the above problem with #.+x+.



>> That said, if you want the value be computed only once, then you can
>> use LOAD-TIME-VALUE to have it evaluated only at that time:
>> 
>> -------------------(/tmp/a.lisp)-------------------------------
>> (defconstant +x+ (load-time-value (print (gensym))))
>> ---------------------------------------------------------------
>> 
>> 
>> C/USER[8]> (compile-file "/tmp/a.lisp")
>> ;; Compiling file /tmp/a.lisp ...
>> ;; Wrote file /tmp/a.fas
>> 0 errors, 0 warnings
>> #P"/private/tmp/a.fas" ;
>> NIL ;
>> NIL
>> C/USER[9]> (load "/tmp/a.fas")
>> ;; Loading file /tmp/a.fas ...
>> #:G10912 
>> ;; Loaded file /tmp/a.fas
>> T
>> C/USER[10]>
>
> I presume you're using CLisp, which already does the Right Thing with 
> defconstant even without the use of LOAD-TIME-VALUE.  Using 
> LOAD-TIME-VALUE does not solve the problem in CCL.  In fact, using 
> LOAD-TIME-VALUE makes the problem worse.  It is not even necessary to 
> re-load the fasl file in order to get two different values of FOO.  
> Merely compiling the file is enough:
>
> [···@mickey:~]$ cat test.lisp
> (eval-when (:compile-toplevel :load-toplevel :execute)

My example took the very special care of not using eval-when!


> (defconstant foo (load-time-value (get-internal-real-time)))

eval-when defeats load-time-value.


> (defun foo () foo)
> )
> [···@mickey:~]$ ccl -n
> Welcome to Clozure Common Lisp Version 1.4-dev-r12255M-trunk  
> (DarwinX8664)!
> ? (compile-file "test.lisp")
> #P"/Users/ron/test.dx64fsl"
> NIL
> NIL
> ? (eq foo (foo))
> NIL

You didn't load /Users/ron/test.dx64fsl, so you're fully in
implementation dependant behavior.

> Is this conclusive evidence of a bug in CCL?

Without a specification, there cannot be a bug.


-- 
__Pascal Bourguignon__
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-77D344.18120221062009@news.albasani.net>
In article <··············@galatea.local>,
 ···@informatimago.com (Pascal J. Bourguignon) wrote:

> Ron Garret <·········@flownet.com> writes:
> 
> > In article <··············@galatea.local>,
> >  ···@informatimago.com (Pascal J. Bourguignon) wrote:
> >
> >> Ron Garret <·········@flownet.com> writes:
> >> 
> >> > Consider the following code:
> >> >
> >> > (eval-when (:load-toplevel :compile-toplevel :execute)
> >> >
> >> >   (defconstant foo ...)
> >> >
> >> >   (defun foo () foo)
> >> >
> >> > )
> >> >
> >> > Are there any circumstances under which, in an ANSI-compliant 
> >> > implementation of CL, (equal foo (foo)) can return NIL?
> >> 
> >> Indeed, but not in conforming code.
> >> 
> >>     A constant defined by defconstant can be redefined with
> >>     defconstant. However, the consequences are undefined if an attempt
> >>     [...]
> >>     to assign it to a different value using a subsequent defconstant.
> >
> > That's true.  But there are legitimate use-cases where this is quite 
> > difficult for the user to achieve.  The particular use-case I'm thinking 
> > of (the one that brought this issue to my attention) is creating a 
> > guardian, that is, a singleton that is used as a distinguished value to 
> > indicate some kind of exceptional condition.  The way I was taught to do 
> > that is with a gensym, but as you can see that can lead to difficulties.
> 
> There should be no difficulty, as long as you don't try to compare the
> values that should be EQL but are not, across different times.  And
> you would have to do some special things to do so.  For example:
> 
>     (defconstant +x+ (gensym))
> 
>     (defun f (x)
>       (case x
>         ((#.+x+) :fails-across-compile/load)))
> 
> 
> Anyways, the advice is to use defconstant only on values of type
> number, character or (interned) symbol.

The problem can be exhibited (as I show below) with any non-idempotent 
function, including for example, get-internal-real-time.  So restricting 
yourself to numbers doesn't help.


> >> > It turns out that there are.  I'll describe what those circumstances are 
> >> > in a moment (makes a good exercise to figure it out on your own).  The 
> >> > question I want to raise is, given that this is the case, is this aspect 
> >> > of DEFCONSTANT's behavior so at odds with intuition that it can be 
> >> > considered broken?  And if so, what, if anything, should be done about 
> >> > it?
> >> 
> >> Yes, in a way we may consider defconstant to be broken.  What can be
> >> done, is avoid using it.
> >
> > Would that be what you recommend?
> 
> Avoid using DEFCONSTANT.  Try DEFPARAMETER, it works better.

Actually, DEFVAR comes closest to doing what I want.  But I also want to 
insure that the value doesn't change or get bound.

> > (defconstant foo (load-time-value (get-internal-real-time)))
> 
> eval-when defeats load-time-value.

Ah.  Hmmm.... that doesn't help then.

rg
From: Scott Burson
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <2e409792-6696-45b5-9474-636a45da86d2@j9g2000prh.googlegroups.com>
On Jun 21, 6:12 pm, Ron Garret <·········@flownet.com> wrote:
>
> Actually, DEFVAR comes closest to doing what I want.  But I also want to
> insure that the value doesn't change or get bound.

Well, there's always DEFINE-SYMBOL-MACRO...

-- Scott
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-AC39B5.23262321062009@news.albasani.net>
In article 
<····································@j9g2000prh.googlegroups.com>,
 Scott Burson <········@gmail.com> wrote:

> On Jun 21, 6:12�pm, Ron Garret <·········@flownet.com> wrote:
> >
> > Actually, DEFVAR comes closest to doing what I want. �But I also want to
> > insure that the value doesn't change or get bound.
> 
> Well, there's always DEFINE-SYMBOL-MACRO...

Doesn't work, because it doesn't insure the value won't change:

[···@mickey:~/Desktop]$ cat test.lisp

(eval-when (:compile-toplevel :load-toplevel :execute)

(define-symbol-macro c7 '#.(gensym))
(defun c7 () c7)

)
[···@mickey:~/Desktop]$ ccl -n
Welcome to Clozure Common Lisp Version 1.4-dev-r12255M-trunk  
(DarwinX8664)!
? (compile-file "test.lisp")
#P"/Users/ron/Desktop/test.dx64fsl"
NIL
NIL
? (defun foo () c7)
FOO
? (eql (foo) c7)
T
? (load "test.dx64fsl")
#P"/Users/ron/Desktop/test.dx64fsl"
? (eql (foo) c7)
NIL
?
From: Kaz Kylheku
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <20090704075344.622@gmail.com>
On 2009-06-22, Ron Garret <·········@flownet.com> wrote:
> In article 
><····································@j9g2000prh.googlegroups.com>,
>  Scott Burson <········@gmail.com> wrote:
>
>> On Jun 21, 6:12 pm, Ron Garret <·········@flownet.com> wrote:
>> >
>> > Actually, DEFVAR comes closest to doing what I want.  But I also want to
>> > insure that the value doesn't change or get bound.
>> 
>> Well, there's always DEFINE-SYMBOL-MACRO...
>
> Doesn't work, because it doesn't insure the value won't change:
>
> [···@mickey:~/Desktop]$ cat test.lisp
>
> (eval-when (:compile-toplevel :load-toplevel :execute)
>
> (define-symbol-macro c7 '#.(gensym))
> (defun c7 () c7)

Right; you get a different instance of the c7 macro when compiling and loading.

It's evaluated again, just like the initializing value of defconstant.

How about this:

  ;; macro only at compile time
  (eval-when (:compile-toplevel)
   (define-symbol-macro c7 '#.(gensym)))

  ;; function only available in compiled form
  (eval-when (:load-toplevel)
   (defun c7 () c7))

Now the problem goes away: there is /no/ C7 symbol macro when you load
the object file.  And if you load the source file, there is no c7
function.

Just like in C, there are no more #define constants when you're loading .o
files. And you can't run source without compiling it. (That's not real
programming; you're supposed to edit, compile, then run, right?)

So, everything is cool.
From: Kaz Kylheku
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <20090704083602.686@gmail.com>
On 2009-06-22, Kaz Kylheku <········@gmail.com> wrote:
> On 2009-06-22, Ron Garret <·········@flownet.com> wrote:
>> In article 
>><····································@j9g2000prh.googlegroups.com>,
>>  Scott Burson <········@gmail.com> wrote:
>>
>>> On Jun 21, 6:12 pm, Ron Garret <·········@flownet.com> wrote:
>>> >
>>> > Actually, DEFVAR comes closest to doing what I want.  But I also want to
>>> > insure that the value doesn't change or get bound.
>>> 
>>> Well, there's always DEFINE-SYMBOL-MACRO...
>>
>> Doesn't work, because it doesn't insure the value won't change:
>>
>> [···@mickey:~/Desktop]$ cat test.lisp
>>
>> (eval-when (:compile-toplevel :load-toplevel :execute)
>>
>> (define-symbol-macro c7 '#.(gensym))
>> (defun c7 () c7)
>
> Right; you get a different instance of the c7 macro when compiling and
> loading.
>
> It's evaluated again, just like the initializing value of defconstant.
>
> How about this:
>
>   ;; macro only at compile time
>   (eval-when (:compile-toplevel)
>    (define-symbol-macro c7 '#.(gensym)))
>
>   ;; function only available in compiled form
>   (eval-when (:load-toplevel)
>    (defun c7 () c7))

But seriously, how does this fare on Clozure?

  ;; constant definition for compile time (and source loading)

  (eval-when (:compile-toplevel :execute)
    (define-symbol-macro c7 '#.(gensym)))

  ;; function to return value of constant:
  ;; - if this is compiled, c7 is folded by macroexpansion 
  ;;   to return the gensym  set up by the above definition, 
  ;;   and that gensym is externalized into the compiled file.
  ;;   See CLHS 3.2.4.2.2: uninterned symbols are externalizeable, 
  ;;   with a similarity based on their names!!!
  ;; - if a compiled form of this is being loaded, then the loader will
  ;;   manufacture a gensym similar to the one that existed
  ;;   at compile time; i.e. it will create a symbol
  ;;   with the same name as if by MAKE-SYMBOL.
  ;; - if this is evaluated as source, then everything
  ;;   is cool; the function refers to c7, which is set
  ;;   up as a macro constant thanks to :execute above.

  (defun c7 () c7)

  ;; load-time constant: now that the compiled file
  ;; is loaded, we make c7 a synonym for the function
  ;; call (c7). Thus (eq c7 (c7)) is assured.

  (eval-when (:load-toplevel)
    (define-symbol-macro c7 (c7)))

See: two different definitions for diferent situations, creating the
illusion of one consistent constant.

I suppose we could go as far as:

  (eval-when (:load-toplevel)
    (eval `(define-symbol-macro c7 ',(c7))))

Now c7 macroexpands to the actual symbol, quoted, similarly to the
way it did at compile time.
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-D81FAE.18461622062009@news.albasani.net>
In article <··················@gmail.com>,
 Kaz Kylheku <········@gmail.com> wrote:

> 
> But seriously, how does this fare on Clozure?
> 
>   ;; constant definition for compile time (and source loading)
> 
>   (eval-when (:compile-toplevel :execute)
>     (define-symbol-macro c7 '#.(gensym)))
> 
>   ;; function to return value of constant:
>   ;; - if this is compiled, c7 is folded by macroexpansion 
>   ;;   to return the gensym  set up by the above definition, 
>   ;;   and that gensym is externalized into the compiled file.
>   ;;   See CLHS 3.2.4.2.2: uninterned symbols are externalizeable, 
>   ;;   with a similarity based on their names!!!
>   ;; - if a compiled form of this is being loaded, then the loader will
>   ;;   manufacture a gensym similar to the one that existed
>   ;;   at compile time; i.e. it will create a symbol
>   ;;   with the same name as if by MAKE-SYMBOL.
>   ;; - if this is evaluated as source, then everything
>   ;;   is cool; the function refers to c7, which is set
>   ;;   up as a macro constant thanks to :execute above.
> 
>   (defun c7 () c7)
> 
>   ;; load-time constant: now that the compiled file
>   ;; is loaded, we make c7 a synonym for the function
>   ;; call (c7). Thus (eq c7 (c7)) is assured.
> 
>   (eval-when (:load-toplevel)
>     (define-symbol-macro c7 (c7)))
> 
> See: two different definitions for diferent situations, creating the
> illusion of one consistent constant.

That works insofar as (eq c7 (c7)) returns T.  However, it's not really 
what I want.  The main reason I want to use DEFCONSTANT is to prevent c7 
from being reassigned or rebound.  If C7 is a symbol macro I don't get 
that guarantee.  If I were willing to rely on the user not to assign or 
bind c7 I could just use DEFVAR and be done with it.

rg
From: Madhu
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <m38wjjemhj.fsf@moon.robolove.meer.net>
* Ron Garret Wrote on Mon, 22 Jun 2009 18:46:16 -0700:

| The main reason I want to use DEFCONSTANT is to prevent c7 from being
| reassigned or rebound.

This is your fundamental error.  You can't.  

What you want is a particular behaviour of what the Common-Lisp-Spec
specifies as "Undefined Consequence"; where it defines the behaviour of
DEFCONSTANT, which is the wrong tool to get what you want anyway.

If it is not already clear, Portable Common Lisp will not help you here.

The Spec leaves to the discretion of individual implementations what
happens on undefined consequences, and implementations can be as anal
and dumb as they wish.

--
Madhu
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-75AB80.19203322062009@news.albasani.net>
In article <··············@moon.robolove.meer.net>,
 Madhu <·······@meer.net> wrote:

> * Ron Garret Wrote on Mon, 22 Jun 2009 18:46:16 -0700:
> 
> | The main reason I want to use DEFCONSTANT is to prevent c7 from being
> | reassigned or rebound.
> 
> You can't.

Yes, that is what I suspected.  Hence the title question of this thread.

> This is your fundamental error.

My error?  Why is the lack of a feature in CL *my* error?  Isn't CL 
supposed to be the programmable programming language?

rg
From: Madhu
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <m34ou7ejw5.fsf@moon.robolove.meer.net>
* Ron Garret <·······························@news.albasani.net> :
Wrote on Mon, 22 Jun 2009 19:20:33 -0700:

| In article <··············@moon.robolove.meer.net>,
|  Madhu <·······@meer.net> wrote:
|
|> * Ron Garret Wrote on Mon, 22 Jun 2009 18:46:16 -0700:
|> 
|> | The main reason I want to use DEFCONSTANT is to prevent c7 from
|> | being reassigned or rebound.
|> 
|> You can't.
| Yes, that is what I suspected.  Hence the title question of this
| thread.

Yes, And I explained why you cannot: (this part you snipped out)
,----
| What you want is a particular behaviour of what the Common-Lisp-Spec
| specifies as "Undefined Consequence"; where it defines the behaviour of
| DEFCONSTANT, which is the wrong tool to get what you want anyway.
|
| The Spec leaves to the discretion of individual implementations what
| happens on undefined consequences, and implementations can be as anal
| and dumb as they wish.
`----

|> This is your fundamental error.
|
| My error?

Yes, It is a categorical error. If you insist on making it, one must
question both your motives and your honesty.

| Why is the lack of a feature in CL *my* error? 
| Isn't CL supposed to be the programmable programming language?

[There are two questions you pose, both are not necessarily related, and
 they are especially not related in the way you'd like to imply]

Either you do not understand Common Lisp at all, or you have some nasty
political motive behind your post.

Common Lisp is defined by a standard, which is clear on what it
specifies and what it does not specify.  In this thread you want a
feature to behave in a certain way which in "Common Lisp" is by
definition IS SPECIFIED to be UNSPECIFIED.

This is an error on YOUR part.  Obviously Portable Common Lisp will not
help you here, as I've already noted.  Your expectations are flawed.
And your error is unrelated to "Common Lisp being a programmable
programming language."

--
Madhu
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-6E490B.22424222062009@news.albasani.net>
In article <··············@moon.robolove.meer.net>,
 Madhu <·······@meer.net> wrote:


> |> This is your fundamental error.
> |
> | My error?
> 
> Yes, It is a categorical error. If you insist on making it, one must
> question both your motives and your honesty.
> 
> | Why is the lack of a feature in CL *my* error? 
> | Isn't CL supposed to be the programmable programming language?
> 
> [There are two questions you pose, both are not necessarily related, and
>  they are especially not related in the way you'd like to imply]
> 
> Either you do not understand Common Lisp at all,

That's possible.  I've only been programming in Lisp since 1979 (it 
wasn't CL back then of course) so maybe I'm still just a n00b.

> or you have some nasty political motive behind your post.

I suppose if you consider wanting to improve the language to be a nasty 
political motive then yes, I am guilty as charged.  However, that I have 
this agenda is hardly a secret.  I am actually quite famous (some would 
say infamous) for this here on c.l.l.

> Common Lisp is defined by a standard, which is clear on what it
> specifies and what it does not specify.  In this thread you want a
> feature to behave in a certain way which in "Common Lisp" is by
> definition IS SPECIFIED to be UNSPECIFIED.
>
> This is an error on YOUR part.  Obviously Portable Common Lisp will not
> help you here, as I've already noted.  Your expectations are flawed.
> And your error is unrelated to "Common Lisp being a programmable
> programming language."

You do realize that this argument applies to any programming language 
with a standard, right?  The argument doesn't just apply to CL.  If one 
were to accept this view, all critiques of the design of any 
standardized programming language would be invalid, since all such 
critiques would be errors on the part of the one doing the critiquing.  
There would also never be any need to revise any standard because any 
perceived flaw in the existing standard could be written off as a flaw 
in the user's expectations.

Somehow I think there's a problem there somewhere, but I can't quite 
figure out what it could be.

rg
From: Pascal J. Bourguignon
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <87eitbzckx.fsf@galatea.local>
Ron Garret <·········@flownet.com> writes:
> Somehow I think there's a problem there somewhere, but I can't quite 
> figure out what it could be.

The language allows you to express what you want in several ways.  
Why do you insist on expressing it in a way that is unspecified?

If you don't want to do anything nasty(*) with that "constant", or you
can just use DEFVAR instead of DEFCONSTANT.  It will work perfectly
well.

If you need to do something nasty with that "constant", then you must,
as specified by the standard, ensure yourself that you bind it to an
EQL value. So do not use a function such that GENSYM.  It will also
work perfectly well (as long as clients of your library won't do
anything nasty, but then they can always break things in so many
different ways).



(*) for a definition of nasty see my previous post: essentially, it
would mean writing code that requires the "constant" to be eql in both
compilation and run-time, that is using it both as a literal in source
(thru #. for example) and as a value at run-time.  You certainly don't
need to do that, you can always write things so that the value of the
constant is used only at run-time.
-- 
__Pascal Bourguignon__
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-751098.00510323062009@news.albasani.net>
In article <··············@galatea.local>,
 ···@informatimago.com (Pascal J. Bourguignon) wrote:

> Ron Garret <·········@flownet.com> writes:
> > Somehow I think there's a problem there somewhere, but I can't quite 
> > figure out what it could be.
> 
> The language allows you to express what you want in several ways.  
> Why do you insist on expressing it in a way that is unspecified?

I don't.  I'm not insisting on using DEFCONSTANT to do what I want, it 
just seemed like the most natural way to do it when I started.  (And it 
worked just fine until I tried to compile the file.  Then all hell broke 
lose.)

> If you don't want to do anything nasty(*) with that "constant", or you
> can just use DEFVAR instead of DEFCONSTANT.  It will work perfectly
> well.
>
> If you need to do something nasty with that "constant", then you must,
> as specified by the standard, ensure yourself that you bind it to an
> EQL value. So do not use a function such that GENSYM.  It will also
> work perfectly well (as long as clients of your library won't do
> anything nasty, but then they can always break things in so many
> different ways).
> 
> 
> 
> (*) for a definition of nasty see my previous post: essentially, it
> would mean writing code that requires the "constant" to be eql in both
> compilation and run-time, that is using it both as a literal in source
> (thru #. for example) and as a value at run-time.  You certainly don't
> need to do that, you can always write things so that the value of the
> constant is used only at run-time.

My use-case is that I'm writing an iterator module, and I want to define 
a guardian value to signal the end of an iteration.  I need to use the 
value both at compile time (because users might define new iterator 
methods) and at run time (because the iterator code has to test to see 
if the value returned by the iterator is the guardian).  I would also 
like to prevent the user from shooting themselves in the foot by binding 
or assigning the value.

I don't think this is an unreasonable set of requirements, but it 
appears to not be possible to do in CL.  Ideally, I'd like to combine 
the initialization semantics of DEFVAR with the immutability properties 
of DEFCONSTANT.  I don't care how it's done, but it appears to be 
actually impossible.

rg
From: Pascal J. Bourguignon
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <7cy6rjpc9y.fsf@pbourguignon.anevia.com>
Ron Garret <·········@flownet.com> writes:

> In article <··············@galatea.local>,
>  ···@informatimago.com (Pascal J. Bourguignon) wrote:
>
>> Ron Garret <·········@flownet.com> writes:
>> > Somehow I think there's a problem there somewhere, but I can't quite 
>> > figure out what it could be.
>> 
>> The language allows you to express what you want in several ways.  
>> Why do you insist on expressing it in a way that is unspecified?
>
> I don't.  I'm not insisting on using DEFCONSTANT to do what I want, it 
> just seemed like the most natural way to do it when I started.  (And it 
> worked just fine until I tried to compile the file.  Then all hell broke 
> lose.)

I agree that some operator names are misleading.

For example, in general you will want DEFPARAMETER instea of DEFVAR.
DEFVAR should be used only in the very special case where you need to
keep the value of a running process while reloading the code...

If you read closely the documentation of emacs lisp defconst, you
might notice that its semantic is exactly that of CL:DEFPARAMETER...


>> If you don't want to do anything nasty(*) with that "constant", or you
>> can just use DEFVAR instead of DEFCONSTANT.  It will work perfectly
>> well.
>>
>> If you need to do something nasty with that "constant", then you must,
>> as specified by the standard, ensure yourself that you bind it to an
>> EQL value. So do not use a function such that GENSYM.  It will also
>> work perfectly well (as long as clients of your library won't do
>> anything nasty, but then they can always break things in so many
>> different ways).
>> 
>> 
>> 
>> (*) for a definition of nasty see my previous post: essentially, it
>> would mean writing code that requires the "constant" to be eql in both
>> compilation and run-time, that is using it both as a literal in source
>> (thru #. for example) and as a value at run-time.  You certainly don't
>> need to do that, you can always write things so that the value of the
>> constant is used only at run-time.
>
> My use-case is that I'm writing an iterator module, and I want to define 
> a guardian value to signal the end of an iteration.  I need to use the 
> value both at compile time (because users might define new iterator 
> methods) and at run time (because the iterator code has to test to see 
> if the value returned by the iterator is the guardian).  

I doubt you really need to use the value at compilation time. (I doubt
you have to do anything nasty).

If you want to allow the use of that value in an eql specializer, then
it will have to be EQL across the compilation / run-time chasm, so it
cannot be generated by gensym.

(defpackage "MY-SPECIAL-VALUES" (:use) (:export "+ITEREND+"))
(defconstant my-special-values:+iterend+ 'my-special-values:+iterend+)
(import 'my-special-values:+iterend+)

(defmethod iterate-or-whatever ((seq (eql +iterend+))) :done)


But I see from the example in your other post and rg-utils.lisp that
you don't need it at compilation time and are not doing anything nasty
with it, so a mere DEFPARAMETER or DEFVAR will do.


> I would also 
> like to prevent the user from shooting themselves in the foot by binding 
> or assigning the value.

Then use a symbol macro.  Notice that defconstant doesn't prevent the
user to assign a value to the constant _variable_.  Only CL says it
has undefined consequences.  The user is always free to shoot himself
in the feet.


> I don't think this is an unreasonable set of requirements, but it 
> appears to not be possible to do in CL.  Ideally, I'd like to combine 
> the initialization semantics of DEFVAR with the immutability properties 
> of DEFCONSTANT.  I don't care how it's done, but it appears to be 
> actually impossible.

DEFCONSTANT doesn't imply any immutability.

First:

    defconstant causes the global variable named by name to be given a
    value that is the result of evaluating initial-value.

So, DEFCONSTANT defines a VARIABLE.

Next:

     A constant defined by defconstant can be redefined with defconstant. 

So you can redefine a VARIABLE defined by DEFCONSTANT.

Then: 

     However, the consequences are undefined if an attempt is made
     to assign a value to the symbol using another operator, or to
     assign it to a different value using a subsequent
     defconstant.

But if you do so with a different (EQL) value, then the standard
doesn't say what happens.


There's absolutely no immutability infered.


I know it's a little hard to understand.  Once upon a time, I was
presented a little Macintosh program where you had to order objects
represented by little icons according to their relative weights.
There was a balance to let you compare the weight of two icons. Of
course I put the elephant as the most heavy, without even trying,
since it's well known that elephants are the most heavy.  Well, not
here.  The elephant icon didn't represent a true animal, but a little
figurine and was lighter than what was represented by an apple icon.


Well, here it's the same, you have an operator DEFCONSTANT that does
some strange things, what what it does has nothing to do with the
constants or immutability its name may make you think about.

-- 
__Pascal Bourguignon__
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-E3C6B3.10254723062009@news.albasani.net>
In article <··············@pbourguignon.anevia.com>,
 ···@informatimago.com (Pascal J. Bourguignon) wrote:

> I doubt you really need to use the value at compilation time.

I'm sure I don't.  The only thing I really need is immutability.  And I 
thought the only way I coyld get immutability in CL is with DEFCONSTANT, 
and that at least potentially gives me a compile time value whether I 
like it or not.  But see below...

> > I would also 
> > like to prevent the user from shooting themselves in the foot by binding 
> > or assigning the value.
> 
> Then use a symbol macro.  Notice that defconstant doesn't prevent the
> user to assign a value to the constant _variable_.  Only CL says it
> has undefined consequences.  The user is always free to shoot himself
> in the feet.

Wow, you're right.  I could have sworn it was an error (every 
implementation I've tried makes it an error) but you're right, it's not.  
Damn.

So there really is no way to make an immutable binding in portable CL.

Hmm....

rg
From: Duane Rettig
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <35913e98-c73c-4b7c-9212-22b33166b2af@12g2000pri.googlegroups.com>
On Jun 23, 10:25 am, Ron Garret <·········@flownet.com> wrote:
> In article <··············@pbourguignon.anevia.com>,
>  ····@informatimago.com (Pascal J. Bourguignon) wrote:
>
> > I doubt you really need to use the value at compilation time.
>
> I'm sure I don't.  The only thing I really need is immutability.  And I
> thought the only way I coyld get immutability in CL is with DEFCONSTANT,
> and that at least potentially gives me a compile time value whether I
> like it or not.  But see below...
>
> > > I would also
> > > like to prevent the user from shooting themselves in the foot by binding
> > > or assigning the value.
>
> > Then use a symbol macro.  Notice that defconstant doesn't prevent the
> > user to assign a value to the constant _variable_.  Only CL says it
> > has undefined consequences.  The user is always free to shoot himself
> > in the feet.
>
> Wow, you're right.  I could have sworn it was an error (every
> implementation I've tried makes it an error) but you're right, it's not.  
> Damn.
>
> So there really is no way to make an immutable binding in portable CL.

Not true; anything can be made as immutable as any other thing in CL,
by not providing the means to mutate it under normal circumstances.
What I perceive is your problem is that you are asking for a kind of
immutability that CL doesn't give you, whether for bindings, objects,
or anything else.  If you look at the definition of immutability,
you'll find that there are _no_ guarantees at all to the user.

Duane
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-CCC141.16574623062009@news.albasani.net>
In article 
<····································@12g2000pri.googlegroups.com>,
 Duane Rettig <·····@franz.com> wrote:

> On Jun 23, 10:25�am, Ron Garret <·········@flownet.com> wrote:
> > In article <··············@pbourguignon.anevia.com>,
> > ·····@informatimago.com (Pascal J. Bourguignon) wrote:
> >
> > > I doubt you really need to use the value at compilation time.
> >
> > I'm sure I don't. �The only thing I really need is immutability. �And I
> > thought the only way I coyld get immutability in CL is with DEFCONSTANT,
> > and that at least potentially gives me a compile time value whether I
> > like it or not. �But see below...
> >
> > > > I would also
> > > > like to prevent the user from shooting themselves in the foot by binding
> > > > or assigning the value.
> >
> > > Then use a symbol macro. �Notice that defconstant doesn't prevent the
> > > user to assign a value to the constant _variable_. �Only CL says it
> > > has undefined consequences. �The user is always free to shoot himself
> > > in the feet.
> >
> > Wow, you're right. �I could have sworn it was an error (every
> > implementation I've tried makes it an error) but you're right, it's not. �
> > Damn.
> >
> > So there really is no way to make an immutable binding in portable CL.
> 
> Not true; anything can be made as immutable as any other thing in CL,
> by not providing the means to mutate it under normal circumstances.
> What I perceive is your problem is that you are asking for a kind of
> immutability that CL doesn't give you, whether for bindings, objects,
> or anything else.  If you look at the definition of immutability,
> you'll find that there are _no_ guarantees at all to the user.

Yep, that's exactly right.  I thought DEFCONSTANT was unique in that it 
provided an immutability guarantee.  In fact, I thought that was what 
DEFCONSTANT was *for*, since every CL I've ever used in fact provides 
immutability of variables defined by DEFCONSTANT.  I was so convinced of 
this that when I discovered this behavior I actually filed a bug report 
with my vendor.

Say, I'm glad you chimed in, Duane, because you're probably uniquely 
qualified to answer this question: if DEFCONSTANT is not for providing 
an immutability guarantee, what is it for?  What can you do with 
DEFCONSTANT in portable CL that you can't do with a symbol macro?

rg
From: Duane Rettig
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <c395d253-3a33-439f-8630-418d589d04c6@o5g2000prh.googlegroups.com>
On Jun 23, 4:57 pm, Ron Garret <·········@flownet.com> wrote:
> In article
> <····································@12g2000pri.googlegroups.com>,
>  Duane Rettig <·····@franz.com> wrote:
>
>
>
>
>
> > On Jun 23, 10:25 am, Ron Garret <·········@flownet.com> wrote:
> > > In article <··············@pbourguignon.anevia.com>,
> > >  ····@informatimago.com (Pascal J. Bourguignon) wrote:
>
> > > > I doubt you really need to use the value at compilation time.
>
> > > I'm sure I don't.  The only thing I really need is immutability.  And I
> > > thought the only way I coyld get immutability in CL is with DEFCONSTANT,
> > > and that at least potentially gives me a compile time value whether I
> > > like it or not.  But see below...
>
> > > > > I would also
> > > > > like to prevent the user from shooting themselves in the foot by binding
> > > > > or assigning the value.
>
> > > > Then use a symbol macro.  Notice that defconstant doesn't prevent the
> > > > user to assign a value to the constant _variable_.  Only CL says it
> > > > has undefined consequences.  The user is always free to shoot himself
> > > > in the feet.
>
> > > Wow, you're right.  I could have sworn it was an error (every
> > > implementation I've tried makes it an error) but you're right, it's not.  
> > > Damn.
>
> > > So there really is no way to make an immutable binding in portable CL.
>
> > Not true; anything can be made as immutable as any other thing in CL,
> > by not providing the means to mutate it under normal circumstances.
> > What I perceive is your problem is that you are asking for a kind of
> > immutability that CL doesn't give you, whether for bindings, objects,
> > or anything else.  If you look at the definition of immutability,
> > you'll find that there are _no_ guarantees at all to the user.
>
> Yep, that's exactly right.  I thought DEFCONSTANT was unique in that it
> provided an immutability guarantee.  In fact, I thought that was what
> DEFCONSTANT was *for*, since every CL I've ever used in fact provides
> immutability of variables defined by DEFCONSTANT.  I was so convinced of
> this that when I discovered this behavior I actually filed a bug report
> with my vendor.
>
> Say, I'm glad you chimed in, Duane, because you're probably uniquely
> qualified to answer this question: if DEFCONSTANT is not for providing
> an immutability guarantee, what is it for?  What can you do with
> DEFCONSTANT in portable CL that you can't do with a symbol macro?

Well, to define a constant?

Seriously, if the guarantees had been toward immutability, then I
would imagine that it would have been called something with more
punch, like defimmutable.  But defconstant defines a constant
variable, which is defined as a variable whose value is not changed,
and that assertion is based on the user following all of the Semantic
Constraints (3.2.2.3) which are put forth in order "to minimize the
observable differences between compiled and interpreted programs".
One of these is for constant variables, which have a bullet on that
page:

 "Constant variables defined in the compilation environment must have
a similar value at run time. A reference to a constant variable in
source code is equivalent to a reference to a literal object that is
the value of the constant variable."

If this constraint isn't met, the guarantee can't be met.

On a broader subject, the whole concept of mutability is vaguely
perplexing to me; ever since I got into the Lisp business, I've seen
hardware implementors that think there really is such a concept as
"text" vs "data" (as in mutually exclusive).  But of course text
memory _must_ be writable, otherwise how can one load up the program
into the "read-only" space?  I finally convince the vendors to think
outside the box (in order not to be limited by what the program can
see).  But that outside the box thinking is nothing more than meta-
thought, and that's just what Lisp does best anyway...

Duane
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-C03C61.00170224062009@news.albasani.net>
In article 
<····································@o5g2000prh.googlegroups.com>,
 Duane Rettig <·····@franz.com> wrote:

> > Say, I'm glad you chimed in, Duane, because you're probably uniquely
> > qualified to answer this question: if DEFCONSTANT is not for providing
> > an immutability guarantee, what is it for? �What can you do with
> > DEFCONSTANT in portable CL that you can't do with a symbol macro?
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> Well, to define a constant?

Why can't I define a constant with a symbol macro?

rg
From: Duane Rettig
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <d2f1d093-371f-448d-889f-bf73608ba3e8@a5g2000pre.googlegroups.com>
On Jun 24, 12:17 am, Ron Garret <·········@flownet.com> wrote:
> In article
> <····································@o5g2000prh.googlegroups.com>,
>  Duane Rettig <·····@franz.com> wrote:
>
> > > Say, I'm glad you chimed in, Duane, because you're probably uniquely
> > > qualified to answer this question: if DEFCONSTANT is not for providing
> > > an immutability guarantee, what is it for?  What can you do with
> > > DEFCONSTANT in portable CL that you can't do with a symbol macro?
>
>                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
>
>
> > Well, to define a constant?
>
> Why can't I define a constant with a symbol macro?

You can, of course.  Just don't ever change it.

Duane
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-1665DF.01243124062009@news.albasani.net>
In article 
<····································@a5g2000pre.googlegroups.com>,
 Duane Rettig <·····@franz.com> wrote:

> On Jun 24, 12:17�am, Ron Garret <·········@flownet.com> wrote:
> > In article
> > <····································@o5g2000prh.googlegroups.com>,
> > �Duane Rettig <·····@franz.com> wrote:
> >
> > > > Say, I'm glad you chimed in, Duane, because you're probably uniquely
> > > > qualified to answer this question: if DEFCONSTANT is not for providing
> > > > an immutability guarantee, what is it for? �What can you do with
> > > > DEFCONSTANT in portable CL that you can't do with a symbol macro?
> >
> > � � � � � � � � � � � � � � � �^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >
> >
> >
> > > Well, to define a constant?
> >
> > Why can't I define a constant with a symbol macro?
> 
> You can, of course.  Just don't ever change it.

Well, yeah, but doesn't the same rule apply to constants defined using 
DEFCONSTANT?  Didn't you just get through explaining to me that the 
burden is on the programmer to insure that "constants" defined by 
DEFCONSTANT don't change?

rg
From: Pascal J. Bourguignon
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <873a9qzdv8.fsf@galatea.local>
Ron Garret <·········@flownet.com> writes:
> Say, I'm glad you chimed in, Duane, because you're probably uniquely 
> qualified to answer this question: if DEFCONSTANT is not for providing 
> an immutability guarantee, what is it for?  What can you do with 
> DEFCONSTANT in portable CL that you can't do with a symbol macro?

You must not think that most CL operators are for the compiler to tell
the programmer something (like, "I will prevent you to modify this
"constant" variable).  This may be true of B&D languages, but not in Lisp.


On the contrary, in Lisp, most of these operators are for YOU, the
programmer, to promise things about your program. 

When you use DEFCONSTANT, you are promizing the compiler that YOU
will always produce the same (EQL) value for that variable and that
YOU won't change it, and won't try to rebind it.

With this promize, the compiler may then take some liberties and
inline that value, since YOU gave it the guarantee that it will always
the same (EQL).

Similarly, eg. with type declarations.


So when you write (defconstant +x+ (gensym)) you are breaking the
promise right away: you are lying to the compiler.

-- 
__Pascal Bourguignon__
From: Russell McManus
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <87hby6lvim.fsf@thelonious.cl-user.org>
Ron Garret <·········@flownet.com> writes:

> My use-case is that I'm writing an iterator module, and I want to
> define a guardian value to signal the end of an iteration.  I need to
> use the value both at compile time (because users might define new
> iterator methods) and at run time (because the iterator code has to
> test to see if the value returned by the iterator is the guardian).  I
> would also like to prevent the user from shooting themselves in the
> foot by binding or assigning the value.

Can't you use the identity of a well known symbol for this?  It's
value would be irrelevant.

-russ
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-7261C5.16584723062009@news.albasani.net>
In article <··············@thelonious.cl-user.org>,
 Russell McManus <···············@yahoo.com> wrote:

> Ron Garret <·········@flownet.com> writes:
> 
> > My use-case is that I'm writing an iterator module, and I want to
> > define a guardian value to signal the end of an iteration.  I need to
> > use the value both at compile time (because users might define new
> > iterator methods) and at run time (because the iterator code has to
> > test to see if the value returned by the iterator is the guardian).  I
> > would also like to prevent the user from shooting themselves in the
> > foot by binding or assigning the value.
> 
> Can't you use the identity of a well known symbol for this?  It's
> value would be irrelevant.
> 
> -russ

Yes.  I've said in a couple of other places in this thread that this is 
an adequate workaround for me, and this discussion is mostly academic.  
But even academic discussions can be interesting.

rg
From: Larry Coleman
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <78cbe83b-d95f-49f5-863f-68f053e8df84@z14g2000yqa.googlegroups.com>
On Jun 23, 1:42 am, Ron Garret <·········@flownet.com> wrote:
>
> I suppose if you consider wanting to improve the language to be a nasty
> political motive then yes, I am guilty as charged.  However, that I have
> this agenda is hardly a secret.  I am actually quite famous (some would
> say infamous) for this here on c.l.l.
>

So how does the language get improved given that the standard would
need to be updated, which doesn't seem likely?
From: Madhu
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <m3vdmncvsq.fsf@moon.robolove.meer.net>
* Ron Garret <·······························@news.albasani.net> :
Wrote on Mon, 22 Jun 2009 22:42:43 -0700:
|> Either you do not understand Common Lisp at all,
|
| That's possible.  I've only been programming in Lisp since 1979 (it
| wasn't CL back then of course) so maybe I'm still just a n00b.

There are many dialects of Lisp.  Your experience with some dialects
does not automatically translate to any proficiency in Common Lisp.
This should be clear from your posts on CL.

|> or you have some nasty political motive behind your post.
|
| I suppose if you consider wanting to improve the language to be a
| nasty political motive then yes, I am guilty as charged.  However,
| that I have this agenda is hardly a secret.  I am actually quite
| famous (some would say infamous) for this here on c.l.l.

The nasty connotation was meant to imply subversiveness; the opposite of
improving.

|> Common Lisp is defined by a standard, which is clear on what it
|> specifies and what it does not specify.  In this thread you want a
|> feature to behave in a certain way which in "Common Lisp" is by
|> definition IS SPECIFIED to be UNSPECIFIED.
|>
|> This is an error on YOUR part.  Obviously Portable Common Lisp will
|> not help you here, as I've already noted.  Your expectations are
|> flawed.  And your error is unrelated to "Common Lisp being a
|> programmable programming language."
|
| You do realize that this argument applies to any programming language
| with a standard, right?

This "argument" was meant to hilight the "category Error" you are
making, and is not an argument about a programming language.

| The argument doesn't just apply to CL.  If one were to accept this
| view, all critiques of the design of any standardized programming
| language would be invalid, since all such critiques would be errors on
| the part of the one doing the critiquing.

In this case I think I've clearly pointed HOW simply your alleged "flaw"
is flawed.  You have no argument except to wrangle over semantics to
some audience based on the authority of "Using LISP since 1979" or
something, not with relevance to facts about "Common Lisp" as defined by
the standard.

| There would also never be any need to revise any standard because any
| perceived flaw in the existing standard could be written off as a flaw
| in the user's expectations.

Incorrect.  Deficiencies can be addressed and the language can be
improved.  However there is no need to use "perceivable flaws" to kick
dust and raise attention to oneself periodically, which is all you are
doing when attacking CL on this forum.  Unfortunately there is always
scope for you to do that because of the nature of the standard.

The specific binding problem you are addressing lies outside the scope
of "CL", as defined by the standard.  You are necessarily in your own
implementation/dialect now.  SBCL's DEFGLOBAL would appear to be a way
in which the problem you are facing can be solved.  Too bad they had to
make DEFCONSTANT unusable to promote this.

--
Madhu
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-D57E14.01125823062009@news.albasani.net>
In article <··············@moon.robolove.meer.net>,
 Madhu <·······@meer.net> wrote:

> * Ron Garret <·······························@news.albasani.net> :
> Wrote on Mon, 22 Jun 2009 22:42:43 -0700:
> |> Either you do not understand Common Lisp at all,
> |
> | That's possible.  I've only been programming in Lisp since 1979 (it
> | wasn't CL back then of course) so maybe I'm still just a n00b.
> 
> There are many dialects of Lisp.  Your experience with some dialects
> does not automatically translate to any proficiency in Common Lisp.
> This should be clear from your posts on CL.

Well, I've been using CL since 1986.


> |> or you have some nasty political motive behind your post.
> |
> | I suppose if you consider wanting to improve the language to be a
> | nasty political motive then yes, I am guilty as charged.  However,
> | that I have this agenda is hardly a secret.  I am actually quite
> | famous (some would say infamous) for this here on c.l.l.
> 
> The nasty connotation was meant to imply subversiveness; the opposite of
> improving.

You need a better dictionary.  Subversive is not the opposite of 
improving.  (In fact, comparing "subversive" to "improving" is, 
ironically enough, a category error.)

> 
> |> Common Lisp is defined by a standard, which is clear on what it
> |> specifies and what it does not specify.  In this thread you want a
> |> feature to behave in a certain way which in "Common Lisp" is by
> |> definition IS SPECIFIED to be UNSPECIFIED.
> |>
> |> This is an error on YOUR part.  Obviously Portable Common Lisp will
> |> not help you here, as I've already noted.  Your expectations are
> |> flawed.  And your error is unrelated to "Common Lisp being a
> |> programmable programming language."
> |
> | You do realize that this argument applies to any programming language
> | with a standard, right?
> 
> This "argument" was meant to hilight the "category Error" you are
> making, and is not an argument about a programming language.
> 

I don't care what it's meant to highlight, the point is that this 
argument is not uniquely applicable to CL (unless you want to argue that 
the CL standard is uniquely flawless).

> | The argument doesn't just apply to CL.  If one were to accept this
> | view, all critiques of the design of any standardized programming
> | language would be invalid, since all such critiques would be errors on
> | the part of the one doing the critiquing.
> 
> In this case I think I've clearly pointed HOW simply your alleged "flaw"
> is flawed.  You have no argument except to wrangle over semantics to
> some audience based on the authority of "Using LISP since 1979" or
> something, not with relevance to facts about "Common Lisp" as defined by
> the standard.
> 

I am not arguing anything, from authority or otherwise.  I'm just asking 
questions.  I only cited my credentials because you raised the 
possibility that I don't understand anything about CL.

> | There would also never be any need to revise any standard because any
> | perceived flaw in the existing standard could be written off as a flaw
> | in the user's expectations.
> 
> Incorrect.  Deficiencies can be addressed and the language can be
> improved.

Glad to hear it.

> However there is no need to use "perceivable flaws" to kick
> dust and raise attention to oneself periodically, which is all you are
> doing when attacking CL on this forum.

How can asking a question be an attack?  And what exactly is the 
distinction between pointing out a deficiency and launching an attack?  
I've actually done neither in this thread.  All I've done is to point 
out a particular aspect of CL's design and ask if other people think 
that it's a deficiency.

For the record, I'm not taking this oblique tack to be subversive, I'm 
doing it because some people on c.l.l. tend to be very touchy and get 
very defensive at the slightest whiff of criticism, so nowadays I'm very 
careful to avoid expressing opinions on my own initiative.  But it's not 
because I have some sinister hidden agenda.  My agenda may be sinister, 
but it's not hidden.  If anyone wants to know what I think all they have 
to do is ask (or look up my old posts).


> The specific binding problem you are addressing lies outside the scope
> of "CL", as defined by the standard.  You are necessarily in your own
> implementation/dialect now.  SBCL's DEFGLOBAL would appear to be a way
> in which the problem you are facing can be solved.  Too bad they had to
> make DEFCONSTANT unusable to promote this.

Indeed.

rg
From: kodifik
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <72d839de-ff3a-4891-94ce-d9dfec0f6258@i6g2000yqj.googlegroups.com>
On Jun 23, 8:24 am, Madhu <·······@meer.net> wrote:
> The nasty connotation was meant to imply subversiveness; the opposite of
> improving.

Since when is subversiveness the opposite of improving?
From: Barry Margolin
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <barmar-665E86.23215522062009@news.eternal-september.org>
In article <··············@moon.robolove.meer.net>,
 Madhu <·······@meer.net> wrote:

> [There are two questions you pose, both are not necessarily related, and
>  they are especially not related in the way you'd like to imply]
> 
> Either you do not understand Common Lisp at all, or you have some nasty
> political motive behind your post.

Either the rumors of Erik Naggum's death are greatly exaggerated, or we 
have evidence of reincarnation....

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Madhu
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <m3zlbzd3oz.fsf@moon.robolove.meer.net>
* Barry Margolin <····························@news.eternal-september.org> :
Wrote on Mon, 22 Jun 2009 23:21:55 -0400:

| Either the rumors of Erik Naggum's death are greatly exaggerated, or we 
| have evidence of reincarnation....

If I recall right, EN's last post on C.L.L was in response to you (BM)
chasing him away

--
Madhu
From: Scott Burson
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <8d01f0fd-ffad-4a3e-b77b-4db71b597744@x1g2000prh.googlegroups.com>
On Jun 22, 6:46 pm, Ron Garret <·········@flownet.com> wrote:
> In article <··················@gmail.com>,
>  Kaz Kylheku <········@gmail.com> wrote:
>
> >   (eval-when (:load-toplevel)
> >     (define-symbol-macro c7 (c7)))
>
> > See: two different definitions for diferent situations, creating the
> > illusion of one consistent constant.
>
> That works insofar as (eq c7 (c7)) returns T.  However, it's not really
> what I want.  The main reason I want to use DEFCONSTANT is to prevent c7
> from being reassigned or rebound.  If C7 is a symbol macro I don't get
> that guarantee.  If I were willing to rely on the user not to assign or
> bind c7 I could just use DEFVAR and be done with it.

Yeah, oh well.

To address your larger point, yes, I have long thought DEFCONSTANT is
not as useful as its inventor(s) probably hoped.

-- Scott
From: Duane Rettig
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <35294ab8-26b6-4845-95e6-2e7f41983849@n7g2000prc.googlegroups.com>
On Jun 23, 2:40 pm, Scott Burson <········@gmail.com> wrote:
> On Jun 22, 6:46 pm, Ron Garret <·········@flownet.com> wrote:
>
> > In article <··················@gmail.com>,
> >  Kaz Kylheku <········@gmail.com> wrote:
>
> > >   (eval-when (:load-toplevel)
> > >     (define-symbol-macro c7 (c7)))
>
> > > See: two different definitions for diferent situations, creating the
> > > illusion of one consistent constant.
>
> > That works insofar as (eq c7 (c7)) returns T.  However, it's not really
> > what I want.  The main reason I want to use DEFCONSTANT is to prevent c7
> > from being reassigned or rebound.  If C7 is a symbol macro I don't get
> > that guarantee.  If I were willing to rely on the user not to assign or
> > bind c7 I could just use DEFVAR and be done with it.
>
> Yeah, oh well.
>
> To address your larger point, yes, I have long thought DEFCONSTANT is
> not as useful as its inventor(s) probably hoped.

That's because you're thinking of defconstant as providing some sort
of "protection", which it does not.  In fact, CL as a whole is an open
language which relies on the goodwill of the programmer to ensure that
things don't get mashed.  If you want a language that provides you
with guarantees of bondage, CL is not the language for you, and due to
those of us who enjoy the freedom (I'm sure you're also one of them)
it's not likely to change in that direction.

Duane
From: Scott Burson
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <75b4d389-f392-4565-a312-b825c6c0e0ae@c18g2000prh.googlegroups.com>
On Jun 23, 3:20 pm, Duane Rettig <·····@franz.com> wrote:
> On Jun 23, 2:40 pm, Scott Burson <········@gmail.com> wrote:
> > I have long thought DEFCONSTANT is
> > not as useful as its inventor(s) probably hoped.
>
> That's because you're thinking of defconstant as providing some sort
> of "protection", which it does not.

There's that, but there's also the issue raised on the SBCL page
someone in this thread linked to, which is that it arguably would be
better if it didn't assign a new value on repeated evaluation (i.e. it
should be more like DEFVAR).

Back to your point, no, I'm not into bondage either, but I do
appreciate helpfulness.  For example, I could imagine an
implementation noting cases where the compiler has integrated a
declared constant into a compiled routine, in such a way that it could
e.g. warn you, when loading a fasl file, if the current value of the
declared constant differs from the one the function was compiled
with.  I don't know if the spec should have mandated such helpfulness,
but I think DEFCONSTANT would be more useful if at least the high-end
implementations did stuff like that.

And thirdly, I'm inclined to agree with Ron that the sentence of the
spec he quoted is unfortunate: "An implementation may choose to
evaluate the value-form at compile time, load time, OR BOTH [emphasis
added]."  I think it should have to be evaluated at compile time,
period, and Ron has given a good argument as to why.

All this is off the cuff, though, and I could be persuaded otherwise.
I just know that over the years I have made little use of DEFCONSTANT.

-- Scott
From: Duane Rettig
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <6064521f-2ca8-4ff1-8232-db2c82b1e99c@s38g2000prg.googlegroups.com>
On Jun 23, 5:09 pm, Scott Burson <········@gmail.com> wrote:
> On Jun 23, 3:20 pm, Duane Rettig <·····@franz.com> wrote:
>
> > On Jun 23, 2:40 pm, Scott Burson <········@gmail.com> wrote:
> > > I have long thought DEFCONSTANT is
> > > not as useful as its inventor(s) probably hoped.
>
> > That's because you're thinking of defconstant as providing some sort
> > of "protection", which it does not.
>
> There's that, but there's also the issue raised on the SBCL page
> someone in this thread linked to, which is that it arguably would be
> better if it didn't assign a new value on repeated evaluation (i.e. it
> should be more like DEFVAR).

Perhaps.  But then your program would be write-only.  What do you do
when you realize that yopu made a mistake?  Lisp is good at allowing
you to redefine things, and so the concept of a truly immutable object
is foreign to Lisp.  Instead, what seems to be meant by some level of
immutability (as is described in the glossary definition of immutable)
is that the means to modify the object is taken away (and this could
be on a graduated basis).

> Back to your point, no, I'm not into bondage either, but I do
> appreciate helpfulness.

As do we all; that's why warnings are given by most implementations
when a constant is redefined.

>  For example, I could imagine an
> implementation noting cases where the compiler has integrated a
> declared constant into a compiled routine, in such a way that it could
> e.g. warn you, when loading a fasl file, if the current value of the
> declared constant differs from the one the function was compiled
> with.  I don't know if the spec should have mandated such helpfulness,
> but I think DEFCONSTANT would be more useful if at least the high-end
> implementations did stuff like that.

Well, there's nothing to prevent an implementation from doing this,
but I certainly wouldn't - how much memory and code overhead do you
think might be involved in remembering that this value 23 compiled
inline into this function's code came from the particular constant you
compiled long ago?

> And thirdly, I'm inclined to agree with Ron that the sentence of the
> spec he quoted is unfortunate: "An implementation may choose to
> evaluate the value-form at compile time, load time, OR BOTH [emphasis
> added]."  I think it should have to be evaluated at compile time,
> period, and Ron has given a good argument as to why.

This is part of the whole environments issue.  Environments are not
well-defined, but they are strongly indicated, and defining forms (as
is defconstant) are free to choose where they place their definitions
(see 3.2.3.1.1).  We've had lengthy conversations about this issue,
and I'd prefer not to rehash it; perhaps someone can point to the
relevant thread.

> All this is off the cuff, though, and I could be persuaded otherwise.
> I just know that over the years I have made little use of DEFCONSTANT.

I probably should have mentioned this to Ron, but I can't spare the
time to do this right now; instead I'll just show it here. This is
what we do when we need something that acts like a constant; we don't
bother hiding it, but it provides very efficient access.  In our hash-
table implementation, the "empty" and "deleted" values are provided by
this style:


(eval-when (:compile-toplevel :execute)
(define-symbol-macro .empty-entry-marker.   (load-time-value *empty-
entry-marker*))
)

(defvar *empty-entry-marker*   (list :empty))

Then in our code we reference .empty-entry-marker.  Mutatis mutandis
for the deleted marker.  This not only gives us markers that are
accessed quickly, but their values are valid across lisp invocations.
Perhaps if necessary I can go into more detail when I have more
time...

Duane
From: Scott Burson
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <75250c78-6785-4dac-aeae-7cb5ec900aaa@j9g2000prh.googlegroups.com>
On Jun 23, 6:17 pm, Duane Rettig <·····@franz.com> wrote:
> On Jun 23, 5:09 pm, Scott Burson <········@gmail.com> wrote:
>
> > On Jun 23, 3:20 pm, Duane Rettig <·····@franz.com> wrote:
>
> > > On Jun 23, 2:40 pm, Scott Burson <········@gmail.com> wrote:
> > > > I have long thought DEFCONSTANT is
> > > > not as useful as its inventor(s) probably hoped.
>
> > > That's because you're thinking of defconstant as providing some sort
> > > of "protection", which it does not.
>
> > There's that, but there's also the issue raised on the SBCL page
> > someone in this thread linked to, which is that it arguably would be
> > better if it didn't assign a new value on repeated evaluation (i.e. it
> > should be more like DEFVAR).
>
> Perhaps.  But then your program would be write-only.  What do you do
> when you realize that you made a mistake?

Perhaps MAKUNBOUND would do for this.  It's rarely enough used that
one is unlikely to call it without thinking.

> > Back to your point, no, I'm not into bondage either, but I do
> > appreciate helpfulness.
>
> As do we all; that's why warnings are given by most implementations
> when a constant is redefined.

Right.

> >  For example, I could imagine an
> > implementation noting cases where the compiler has integrated a
> > declared constant into a compiled routine, in such a way that it could
> > e.g. warn you, when loading a fasl file, if the current value of the
> > declared constant differs from the one the function was compiled
> > with.  I don't know if the spec should have mandated such helpfulness,
> > but I think DEFCONSTANT would be more useful if at least the high-end
> > implementations did stuff like that.
>
> Well, there's nothing to prevent an implementation from doing this,
> but I certainly wouldn't - how much memory and code overhead do you
> think might be involved in remembering that this value 23 compiled
> inline into this function's code came from the particular constant you
> compiled long ago?

This seems a very strange question in an era when a terabyte disc
drive costs under $100.

> I probably should have mentioned this to Ron, but I can't spare the
> time to do this right now; instead I'll just show it here. This is
> what we do when we need something that acts like a constant; we don't
> bother hiding it, but it provides very efficient access.  In our hash-
> table implementation, the "empty" and "deleted" values are provided by
> this style:
>
> (eval-when (:compile-toplevel :execute)
> (define-symbol-macro .empty-entry-marker.   (load-time-value *empty-
> entry-marker*))
> )
>
> (defvar *empty-entry-marker*   (list :empty))
>
> Then in our code we reference .empty-entry-marker.

So you don't try to use DEFCONSTANT for this either.  Sounds like
agreement to me :)

-- Scott
From: Duane Rettig
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <054aacc8-29c9-4c5a-be38-70e90ed1d436@a39g2000pre.googlegroups.com>
On Jun 23, 9:23 pm, Scott Burson <········@gmail.com> wrote:
> On Jun 23, 6:17 pm, Duane Rettig <·····@franz.com> wrote:
>
>
>
>
>
> > On Jun 23, 5:09 pm, Scott Burson <········@gmail.com> wrote:
>
> > > On Jun 23, 3:20 pm, Duane Rettig <·····@franz.com> wrote:
>
> > > > On Jun 23, 2:40 pm, Scott Burson <········@gmail.com> wrote:
> > > > > I have long thought DEFCONSTANT is
> > > > > not as useful as its inventor(s) probably hoped.
>
> > > > That's because you're thinking of defconstant as providing some sort
> > > > of "protection", which it does not.
>
> > > There's that, but there's also the issue raised on the SBCL page
> > > someone in this thread linked to, which is that it arguably would be
> > > better if it didn't assign a new value on repeated evaluation (i.e. it
> > > should be more like DEFVAR).
>
> > Perhaps.  But then your program would be write-only.  What do you do
> > when you realize that you made a mistake?
>
> Perhaps MAKUNBOUND would do for this.  It's rarely enough used that
> one is unlikely to call it without thinking.

But in this "new and improved" CL where defconstant really defines
something that can't be changed, would makunbound then have an effect?

> > >  For example, I could imagine an
> > > implementation noting cases where the compiler has integrated a
> > > declared constant into a compiled routine, in such a way that it could
> > > e.g. warn you, when loading a fasl file, if the current value of the
> > > declared constant differs from the one the function was compiled
> > > with.  I don't know if the spec should have mandated such helpfulness,
> > > but I think DEFCONSTANT would be more useful if at least the high-end
> > > implementations did stuff like that.
>
> > Well, there's nothing to prevent an implementation from doing this,
> > but I certainly wouldn't - how much memory and code overhead do you
> > think might be involved in remembering that this value 23 compiled
> > inline into this function's code came from the particular constant you
> > compiled long ago?
>
> This seems a very strange question in an era when a terabyte disc
> drive costs under $100.

This argument has been given since the beginning of computing, long
before Bill Gates made his famous "nobody will ever need 840K memory"
quip.  We're giving people those terabytes, and it's not enough.  when
more becomes available, it will not be enough.  Besides, it's usually
not available memory that limits the economics of memory usage.

> > I probably should have mentioned this to Ron, but I can't spare the
> > time to do this right now; instead I'll just show it here. This is
> > what we do when we need something that acts like a constant; we don't
> > bother hiding it, but it provides very efficient access.  In our hash-
> > table implementation, the "empty" and "deleted" values are provided by
> > this style:
>
> > (eval-when (:compile-toplevel :execute)
> > (define-symbol-macro .empty-entry-marker.   (load-time-value *empty-
> > entry-marker*))
> > )
>
> > (defvar *empty-entry-marker*   (list :empty))
>
> > Then in our code we reference .empty-entry-marker.
>
> So you don't try to use DEFCONSTANT for this either.  Sounds like
> agreement to me :)

Agreement that defconstant is not the right tool for this situation.
It is a situation similar to what Ron is wanting to do (except for
immutability guarantees), and it works well in Allegro CL, but I don't
know how well it would work in other CLs.  But it was meant to be a
helpful idea for Ron, and thus a non-sequitur, so no, it's not
necessarily agreement in general.

Duane
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-976813.00214424062009@news.albasani.net>
In article 
<····································@a39g2000pre.googlegroups.com>,
 Duane Rettig <·····@franz.com> wrote:

> > > > �For example, I could imagine an
> > > > implementation noting cases where the compiler has integrated a
> > > > declared constant into a compiled routine, in such a way that it could
> > > > e.g. warn you, when loading a fasl file, if the current value of the
> > > > declared constant differs from the one the function was compiled
> > > > with. �I don't know if the spec should have mandated such helpfulness,
> > > > but I think DEFCONSTANT would be more useful if at least the high-end
> > > > implementations did stuff like that.
> >
> > > Well, there's nothing to prevent an implementation from doing this,
> > > but I certainly wouldn't - how much memory and code overhead do you
> > > think might be involved in remembering that this value 23 compiled
> > > inline into this function's code came from the particular constant you
> > > compiled long ago?
> >
> > This seems a very strange question in an era when a terabyte disc
> > drive costs under $100.
> 
> This argument has been given since the beginning of computing, long
> before Bill Gates made his famous "nobody will ever need 840K memory"
> quip.  We're giving people those terabytes, and it's not enough.

That's because they're filling disks with media files.  Even with a 
comprehensive index and cross-reference, it would take an awful lot of 
work to fill a terabyte disk with source code.

rg
From: Scott Burson
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <c7130a28-ad6f-4d29-8581-a8caa83c7405@c18g2000prh.googlegroups.com>
On Jun 23, 10:32 pm, Duane Rettig <·····@franz.com> wrote:
> On Jun 23, 9:23 pm, Scott Burson <········@gmail.com> wrote:
>
> > On Jun 23, 6:17 pm, Duane Rettig <·····@franz.com> wrote:
>
> > > On Jun 23, 5:09 pm, Scott Burson <········@gmail.com> wrote:
>
> > > > On Jun 23, 3:20 pm, Duane Rettig <·····@franz.com> wrote:
>
> > > > > On Jun 23, 2:40 pm, Scott Burson <········@gmail.com> wrote:
> > > > > > I have long thought DEFCONSTANT is
> > > > > > not as useful as its inventor(s) probably hoped.
>
> > > > > That's because you're thinking of defconstant as providing some sort
> > > > > of "protection", which it does not.
>
> > > > There's that, but there's also the issue raised on the SBCL page
> > > > someone in this thread linked to, which is that it arguably would be
> > > > better if it didn't assign a new value on repeated evaluation (i.e. it
> > > > should be more like DEFVAR).
>
> > > Perhaps.  But then your program would be write-only.  What do you do
> > > when you realize that you made a mistake?
>
> > Perhaps MAKUNBOUND would do for this.  It's rarely enough used that
> > one is unlikely to call it without thinking.
>
> But in this "new and improved" CL where defconstant really defines
> something that can't be changed, would makunbound then have an effect?

I think it could, but again this is off the cuff.  I don't have a
fully thought out proposal and I probably won't bother to produce one.

> > > >  For example, I could imagine an
> > > > implementation noting cases where the compiler has integrated a
> > > > declared constant into a compiled routine, in such a way that it could
> > > > e.g. warn you, when loading a fasl file, if the current value of the
> > > > declared constant differs from the one the function was compiled
> > > > with.  I don't know if the spec should have mandated such helpfulness,
> > > > but I think DEFCONSTANT would be more useful if at least the high-end
> > > > implementations did stuff like that.
>
> > > Well, there's nothing to prevent an implementation from doing this,
> > > but I certainly wouldn't - how much memory and code overhead do you
> > > think might be involved in remembering that this value 23 compiled
> > > inline into this function's code came from the particular constant you
> > > compiled long ago?
>
> > This seems a very strange question in an era when a terabyte disc
> > drive costs under $100.
>
> This argument has been given since the beginning of computing, long
> before Bill Gates made his famous "nobody will ever need 840K memory"
> quip.

???  I proposed that for each compiled function the implementation
would remember all values of constants integrated into the compiled
code.  Even constant-heavy code is going to have what, on average --
two or three of these per routine?  How much space do you think we're
talking about here?

I'm not saying this is a very important feature, but I think the
reason not to do it is that it's more trouble to implement than it's
worth, not that the fasl file space requirement would be prohibitive.

-- Scott
From: Duane Rettig
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <79b6729d-0922-40cb-9e56-4079d7c441c7@u9g2000prd.googlegroups.com>
On Jun 24, 7:51 pm, Scott Burson <········@gmail.com> wrote:
> On Jun 23, 10:32 pm, Duane Rettig <·····@franz.com> wrote:
>
>
>
>
>
> > On Jun 23, 9:23 pm, Scott Burson <········@gmail.com> wrote:
>
> > > On Jun 23, 6:17 pm, Duane Rettig <·····@franz.com> wrote:
>
> > > > On Jun 23, 5:09 pm, Scott Burson <········@gmail.com> wrote:
>
> > > > > On Jun 23, 3:20 pm, Duane Rettig <·····@franz.com> wrote:
>
> > > > > > On Jun 23, 2:40 pm, Scott Burson <········@gmail.com> wrote:
> > > > > > > I have long thought DEFCONSTANT is
> > > > > > > not as useful as its inventor(s) probably hoped.
>
> > > > > > That's because you're thinking of defconstant as providing some sort
> > > > > > of "protection", which it does not.
>
> > > > > There's that, but there's also the issue raised on the SBCL page
> > > > > someone in this thread linked to, which is that it arguably would be
> > > > > better if it didn't assign a new value on repeated evaluation (i.e. it
> > > > > should be more like DEFVAR).
>
> > > > Perhaps.  But then your program would be write-only.  What do you do
> > > > when you realize that you made a mistake?
>
> > > Perhaps MAKUNBOUND would do for this.  It's rarely enough used that
> > > one is unlikely to call it without thinking.
>
> > But in this "new and improved" CL where defconstant really defines
> > something that can't be changed, would makunbound then have an effect?
>
> I think it could, but again this is off the cuff.  I don't have a
> fully thought out proposal and I probably won't bother to produce one.

Right; when considering language changes, one must never limit the
thought to just the localized change that is desired, but one must
consider all of the consequent changes that would be needed to make
the language consistent.  I have no doubts you could come up with a
solution, but you would certainly have to think about such a solution
as part of the change and what other conventions you want your
language to follow.

> > > > >  For example, I could imagine an
> > > > > implementation noting cases where the compiler has integrated a
> > > > > declared constant into a compiled routine, in such a way that it could
> > > > > e.g. warn you, when loading a fasl file, if the current value of the
> > > > > declared constant differs from the one the function was compiled
> > > > > with.  I don't know if the spec should have mandated such helpfulness,
> > > > > but I think DEFCONSTANT would be more useful if at least the high-end
> > > > > implementations did stuff like that.
>
> > > > Well, there's nothing to prevent an implementation from doing this,
> > > > but I certainly wouldn't - how much memory and code overhead do you
> > > > think might be involved in remembering that this value 23 compiled
> > > > inline into this function's code came from the particular constant you
> > > > compiled long ago?
>
> > > This seems a very strange question in an era when a terabyte disc
> > > drive costs under $100.
>
> > This argument has been given since the beginning of computing, long
> > before Bill Gates made his famous "nobody will ever need 840K memory"
> > quip.
>
> ???  I proposed that for each compiled function the implementation
> would remember all values of constants integrated into the compiled
> code.  Even constant-heavy code is going to have what, on average --
> two or three of these per routine?  How much space do you think we're
> talking about here?

Are we really talking about space here?  Or even just code? (yes,
these were the choices I gave, but really, is that all you think about
when you hear the word "overhead")?  [And even if you were thinking in
the direction of the terabyte machine, what about running CL on your
iPhone?  How much power consumption would you have to deal with with
"just a few more bytes?"  Of course, all of this overhead could be
stripped away for such a targeted application, but if the language has
to be stripped down in order to deploy, why use CL at all?  Cl would
become so muscular that it would edge itself out of many application
situations it can currently be deployed in.]

But I wasn't talking only about memory space, per se, and I'm glad you
caught the drift of what I really was trying to push you toward:

> I'm not saying this is a very important feature, but I think the
> reason not to do it is that it's more trouble to implement than it's
> worth, not that the fasl file space requirement would be prohibitive.

Yes, _now_ we're talking!  It's all about complexity, and it's also
about departing from the basic flavor of Common Lisp:

- Complexity:

The CL style is to allow constants (they're immutable by agreement
between the user and implementor) to be compiled inline into the
code.  So what happens when a constant is redefined to a new value?
For the sake of discussion, let's ignore that CL says that the results
are implementation dependent; we'll be talking about the "new improved
CL" where constants can indeed be redefined with defined
consequences.  If this is the case, and holding all other factors
steady, consider the code

(defmacro addit (a b c)
  `(+ ,a ,b ,c))

And then consider the function foo

(defun foo (x)
  (addit +my-lifetime-height+ x +my-lifetime-weight+))

Of course, I've depicted these values as constants, but in reality,
they are unlikely to be constants.  In the compiled code, my compiler
transforms this function to a single instruction:

 add <secret-value>,parm0,ret

where <secret-value> is none of your business.

Now, how do I set up my compiler to keep track of this value, which
has no direct connection with the two constants I defined, but which
should in fact change if I changed either of these constants?
Obviously, there could be connections made, either to the source code
(which would always have to be saved) or to some mechanism to dislodge
the constant from the code stream (similar to what update-instance-
for... do in CLOS).  The problem here is that the whole reason for
compilation is to reduce code complexity, and having these hooks to
break these simplifications goes against the goal of compilation.  You
may as well not compile your code at all, in which case you would
almost get what you desire anyway (modulo the implementation's
willingness to change the constant).


- Basic flavor of Common Lisp:

Common Lisp tries to balance between late binding and efficiency.  So
whereas a function can be redefined on the fly, and thus the new
definition can be made available for the next call to that function's
name, there are also provisions for freezing function definitions, via
the guarantees made by the Semantic Constraints in 3.2.2.3 (which are,
like constants not changing, only guarantees if the constraints are
obeyed by the user).  Thus, a function in a file might be called by
another function in that same file, and the implementation is free to
seal that function's definition within the caller, regardless of
whether the called function has been later redefined.  CL thus defines
a pattern that might be described as "late binding, but not too
strict".  It is this tension between late binding and allowing the
most efficient code possible which allows CL to compete successfully
with other low-level languages like C.

The same could be said of constants.  In fact, in my opinion the
purpose of defconstant is to provide a break from the normal late-
binding rules that apply to other variables and to thus allow the
constant to be embedded in the code without regard to the problem of
what to do with the code when the constant is redefined.

Duane
From: Pascal J. Bourguignon
Subject: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <7cy6rgn2el.fsf_-_@pbourguignon.anevia.com>
Duane Rettig <·····@franz.com> writes:

> The problem here is that the whole reason for
> compilation is to reduce code complexity, and having these hooks to
> break these simplifications goes against the goal of compilation.  

This surprize me.

I thought that the purpose of compilation was foremost to optimize
speed.

I'm not sure that it reduces code complexity.  For a start, assembler
is harder to read than high level language.  Then the compiler may
open code, inline, unroll loops, and implement any other kind of trick
which dilutes abstractions a lot, which I understand as rendering the
code more complex, not less.



Perhaps you mean that the target virtual machine is usually simplier
(a single memory vector, a few registers, a few instructions to move
bits),  than the CL virtual machine (with special operators and
notions that are more sophisticated and intertwined).

But the code itself, by consequence of this difference of complexity
of the virtual machines, must be more complex on the simplier VM, at
least when generated by a compiler trying to optimize anything but
readability of the assembler code.

-- 
__Pascal Bourguignon__
From: Duane Rettig
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <347951c7-8b5c-43fb-b6f1-111ef52dfb7e@w31g2000prd.googlegroups.com>
On Jun 25, 1:28 am, ····@informatimago.com (Pascal J. Bourguignon)
wrote:
> Duane Rettig <·····@franz.com> writes:
> > The problem here is that the whole reason for
> > compilation is to reduce code complexity, and having these hooks to
> > break these simplifications goes against the goal of compilation.  
>
> This surprize me.
>
> I thought that the purpose of compilation was foremost to optimize
> speed.

No, although that's usually a by-product, and thus the user tends to
make that a goal.

> I'm not sure that it reduces code complexity.  For a start, assembler
> is harder to read than high level language.

Harder for whom or what?   It's certainly easier to read for the
executing machine.  And we're not talking about readability, but
complexity.  And, by the way, assembler code is not compiled code; it
is also source code which must be assembled in order to execute
directly on a machine.  You might consider assembler to be equivalent
to machine code, because you usually have excellent disassembling
tools, which reintroduce the complexities of mnemonic names,
connections between jump instructions and their target labels
(remember, though, that labels don't actually exist in machine code -
they are just instructions which happen to be the target of the jump).

  Then the compiler may
> open code, inline, unroll loops, and implement any other kind of trick
> which dilutes abstractions a lot, which I understand as rendering the
> code more complex, not less.

Actually, quite the opposite.  A loop is more complex than straight-
line code; it has a branch instruction within it, which is well-
understood to create pipeline stalls, unless the hardware has the
added complexity itself to duplicate effort in order to perform branch
prediction.   No, the simplest code is the fully-unrolled loop which
executes no branches, but which simply performs the required
instructions.  Is it necessarily optimal? No, because code size does
factor into the mix, and so the fact that loops are only unrolled
partially is due to tradeoffs between code complexity and instruction
cache size.

> Perhaps you mean that the target virtual machine is usually simplier
> (a single memory vector, a few registers, a few instructions to move
> bits),  than the CL virtual machine (with special operators and
> notions that are more sophisticated and intertwined).

Yes, of course.

> But the code itself, by consequence of this difference of complexity
> of the virtual machines, must be more complex on the simplier VM, at
> least when generated by a compiler trying to optimize anything but
> readability of the assembler code.

Readability is _not_ the antithesis of complexity.  They are on two
different planes.

Duane
From: Ron Garret
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-AA8A36.18344725062009@news.albasani.net>
In article 
<····································@w31g2000prd.googlegroups.com>,
 Duane Rettig <·····@franz.com> wrote:

> On Jun 25, 1:28�am, ····@informatimago.com (Pascal J. Bourguignon)
> wrote:
> > Duane Rettig <·····@franz.com> writes:
> > > The problem here is that the whole reason for
> > > compilation is to reduce code complexity, and having these hooks to
> > > break these simplifications goes against the goal of compilation. �
> >
> > This surprize me.
> >
> > I thought that the purpose of compilation was foremost to optimize
> > speed.
> 
> No, although that's usually a by-product, and thus the user tends to
> make that a goal.

Whoa.

Duane: Are you distinguishing between compilation and interpretation 
here?  If not, then I think that conflating the two is unnecessarily 
confusing.  And if so, then what exactly is it that a compiler 
"simplifies" more effectively than the corresponding interpreter?

rg
From: Pascal J. Bourguignon
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <874ou3ycb9.fsf@galatea.local>
Ron Garret <·········@flownet.com> writes:

> In article 
> <····································@w31g2000prd.googlegroups.com>,
>  Duane Rettig <·····@franz.com> wrote:
>
>> On Jun 25, 1:28�am, ····@informatimago.com (Pascal J. Bourguignon)
>> wrote:
>> > Duane Rettig <·····@franz.com> writes:
>> > > The problem here is that the whole reason for
>> > > compilation is to reduce code complexity, and having these hooks to
>> > > break these simplifications goes against the goal of compilation. �
>> >
>> > This surprize me.
>> >
>> > I thought that the purpose of compilation was foremost to optimize
>> > speed.
>> 
>> No, although that's usually a by-product, and thus the user tends to
>> make that a goal.
>
> Whoa.
>
> Duane: Are you distinguishing between compilation and interpretation 
> here?  If not, then I think that conflating the two is unnecessarily 
> confusing.  And if so, then what exactly is it that a compiler 
> "simplifies" more effectively than the corresponding interpreter?

As it can be understood by reading the whole sub-thread, Duane means
that the compiler produces a version of the program that is simplier
to 'interpret' or execute.

Indeed, the virtual machine (or the processor) needed to execute the
binary is simplier than a lisp interpreter.

So we could state the purpose of compilation to be to produce a
program that can be executed using simplier means.


-- 
__Pascal Bourguignon__
From: Pascal J. Bourguignon
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <87tz24xdni.fsf@galatea.local>
Duane Rettig <·····@franz.com> writes:

> On Jun 25, 1:28�am, ····@informatimago.com (Pascal J. Bourguignon)
> wrote:
>> Duane Rettig <·····@franz.com> writes:
>> > The problem here is that the whole reason for
>> > compilation is to reduce code complexity, and having these hooks to
>> > break these simplifications goes against the goal of compilation. �
>>
>> This surprize me.
>>
>> I thought that the purpose of compilation was foremost to optimize
>> speed.
>
> No, although that's usually a by-product, and thus the user tends to
> make that a goal.

We wouldn't want to merely translate to a different target machine, if
it didn't allow to run faster.  There'd be no money in compilers.

So if it's not porting a program from one VM to another, and it's not
for speed, why do we want to compile?


>> I'm not sure that it reduces code complexity. �For a start, assembler
>> is harder to read than high level language.
>
> Harder for whom or what?   It's certainly easier to read for the
> executing machine.  And we're not talking about readability, but
> complexity.  And, by the way, assembler code is not compiled code; it
> is also source code which must be assembled in order to execute
> directly on a machine.  You might consider assembler to be equivalent
> to machine code, because you usually have excellent disassembling
> tools, which reintroduce the complexities of mnemonic names,
> connections between jump instructions and their target labels
> (remember, though, that labels don't actually exist in machine code -
> they are just instructions which happen to be the target of the jump).

Yes, with plain assemblers and simple enough processors, there's a
quasi bijection between assembler text and binary.  But I'm aware of
the difference, only I don't think it's signficative.  My bet is that
assembler and binary have a complexity ratio close to 1 (see below).


>  �Then the compiler may
>> open code, inline, unroll loops, and implement any other kind of trick
>> which dilutes abstractions a lot, which I understand as rendering the
>> code more complex, not less.
>
> Actually, quite the opposite.  A loop is more complex than straight-
> line code; it has a branch instruction within it, which is well-
> understood to create pipeline stalls, unless the hardware has the
> added complexity itself to duplicate effort in order to perform branch
> prediction.   No, the simplest code is the fully-unrolled loop which
> executes no branches, but which simply performs the required
> instructions.  Is it necessarily optimal? No, because code size does
> factor into the mix, and so the fact that loops are only unrolled
> partially is due to tradeoffs between code complexity and instruction
> cache size.


We fight complexity with abstractions.  Which is mostly inventing new
levels of source code generating the existing lower level of lisp, VOP
or binary.  If adding an abstraction didn't reduce the complexity we
wouldn't do it, we'd keep programming in assembler.

Another way to see it is to consider that a complex object is harder
to compress than a simplier object.

I'd assert that:

1- Program sources are more compressible than program binaries.

2- Compressed sources of a given program are smaller than 
   compressed binaries of the same program.

Which would tend to show that sources are less complex than binaries. 

Let's take a sizable commercial embedded application as example:

                              text         bzip2 -9    Compression ratio
Source (C++)                 16435727       1304451     0.079
Binary (x86, stripped)       10587432       3039129     0.287
Complexity ratio (binary/source):             2.330

(I consider coarsely bzip2 -9 to be a majoration of Kolmogorov's
complexity).


-- 
__Pascal Bourguignon__
From: Duane Rettig
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <6a94cfa5-4f6e-4edd-aee1-536dcce2ec71@f10g2000vbf.googlegroups.com>
On Jun 25, 1:27 pm, ····@informatimago.com (Pascal J. Bourguignon)
wrote:
> Duane Rettig <·····@franz.com> writes:
> > On Jun 25, 1:28 am, ····@informatimago.com (Pascal J. Bourguignon)
> > wrote:
> >> Duane Rettig <·····@franz.com> writes:
> >> > The problem here is that the whole reason for
> >> > compilation is to reduce code complexity, and having these hooks to
> >> > break these simplifications goes against the goal of compilation.  
>
> >> This surprize me.
>
> >> I thought that the purpose of compilation was foremost to optimize
> >> speed.
>
> > No, although that's usually a by-product, and thus the user tends to
> > make that a goal.
>
> We wouldn't want to merely translate to a different target machine, if
> it didn't allow to run faster.  There'd be no money in compilers.

There's money in compilers?  :)

> So if it's not porting a program from one VM to another, and it's not
> for speed, why do we want to compile?

Of course _you_ want to compile for speed.  But you're looking at my
original paragraph from the wrong point of view; it was never meant to
explore the reasons why _we_ use compilers, but instead from the point
of view of the compiler itself.  I suppose I should have used the word
"goal" or "purpose" instead of "reason", as if to say what the
compiler's goal is.  Our previous conversation about defconstant
presupposes the need for the compiler, because without the compiler
most of the issue goes away.  So I was using "reason" here in more of
a limited sense which might be more appropriately described as "goal"
or "purpose", not in the larger sense of "why is it useful"...

> >> I'm not sure that it reduces code complexity.  For a start, assembler
> >> is harder to read than high level language.
>
> > Harder for whom or what?   It's certainly easier to read for the
> > executing machine.  And we're not talking about readability, but
> > complexity.  And, by the way, assembler code is not compiled code; it
> > is also source code which must be assembled in order to execute
> > directly on a machine.  You might consider assembler to be equivalent
> > to machine code, because you usually have excellent disassembling
> > tools, which reintroduce the complexities of mnemonic names,
> > connections between jump instructions and their target labels
> > (remember, though, that labels don't actually exist in machine code -
> > they are just instructions which happen to be the target of the jump).
>
> Yes, with plain assemblers and simple enough processors, there's a
> quasi bijection between assembler text and binary.  But I'm aware of
> the difference, only I don't think it's signficative.  My bet is that
> assembler and binary have a complexity ratio close to 1 (see below).

Yes, close to 1, but I was only making a point.  We tend to think in
terms of assembler, but that is because we tend to have many tools
that can perform the abstraction needed to look at assembler source
rather than binary code.  Have you ever been on a machine which does
not have gdb, with all of its disassembling capabilities, and had to
perform the calculations of what instruction you're observing, or if
it happens to be a branch instruction, to what address the branch
location points?  A few hours working like this might not change your
mind as to the one-to-one nature of assembler to machine code, but it
would certainly give you a different perspective.  Long before I
became a software engineer (and even before I had become a hardware
engineer before that) I developed such an appreciation for assemblers
and disassemblers by trying to hand-disassemble hex dumps of old 6802
programs...

> >   Then the compiler may
> >> open code, inline, unroll loops, and implement any other kind of trick
> >> which dilutes abstractions a lot, which I understand as rendering the
> >> code more complex, not less.
>
> > Actually, quite the opposite.  A loop is more complex than straight-
> > line code; it has a branch instruction within it, which is well-
> > understood to create pipeline stalls, unless the hardware has the
> > added complexity itself to duplicate effort in order to perform branch
> > prediction.   No, the simplest code is the fully-unrolled loop which
> > executes no branches, but which simply performs the required
> > instructions.  Is it necessarily optimal? No, because code size does
> > factor into the mix, and so the fact that loops are only unrolled
> > partially is due to tradeoffs between code complexity and instruction
> > cache size.
>
> We fight complexity with abstractions.  Which is mostly inventing new
> levels of source code generating the existing lower level of lisp, VOP
> or binary.  If adding an abstraction didn't reduce the complexity we
> wouldn't do it, we'd keep programming in assembler.

Yes, you're thinking about this backwards.  Abstractions are in the
upward (i.e. on the scale of low-level to high-level) direction, which
reduces complexity for the user, but which also _increases_ complexity
for the tools that are performing the abstraction for you.

Consider a simple example at the hardware level:  If you were wanting
to write a cos() function in assembler from scratch, on a RISC machine
it would be a very complex set of assembler instructions, which would
likely be fairly large in code space (at least several thousand
instructions (in fact, on an Alpha it seems to be about 3600 bytes).
In a CISC machine (where, interestingly, the first C stands for
Complex), where the machine has increased its complexity so that the
user doesn't have to deal with it, the disassembled cos function is
more like 38 bytes, most of which is taken up in handling edge cases
that the fcos instruction (on x87 hardware) doesn't handle.  Again,
from the user's point of view, less complex.  From the compiler's
point of view, more complex.

So, in going the other direction, from source code to assembler/
machine code (or, in the case of cos, from the single complex
instruction to the thousands of instructions that would have been
required to implement it if it weren't there), the direction from high-
level to low level is one of increasing simplicity.  More
instructions, yes.  But also more simplicity.  The 3600 bytes worth of
instructions to implement cos on the alpha are all much simpler than
the single fcos instruction on the x87.

 [snip]

I don't buy a correlation between compressibility and simplicity any
more than I buy a forced correlation between LOC generated and
paycheck.  Numbers can be generated and show whatever you please, but
there are too many factors involved to draw such a simplistic
conclusion.

Duane
From: Pascal J. Bourguignon
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <87fxdnykxk.fsf@galatea.local>
Duane Rettig <·····@franz.com> writes:

> On Jun 25, 1:27�pm, ····@informatimago.com (Pascal J. Bourguignon)
> wrote:
>> Duane Rettig <·····@franz.com> writes:
>> > On Jun 25, 1:28�am, ····@informatimago.com (Pascal J. Bourguignon)
>> > wrote:
>> >> Duane Rettig <·····@franz.com> writes:
>> >> > The problem here is that the whole reason for
>> >> > compilation is to reduce code complexity, and having these hooks to
>> >> > break these simplifications goes against the goal of compilation. �
>>
>> [...]
>>
>> We fight complexity with abstractions. �Which is mostly inventing new
>> levels of source code generating the existing lower level of lisp, VOP
>> or binary. �If adding an abstraction didn't reduce the complexity we
>> wouldn't do it, we'd keep programming in assembler.
>
> Yes, you're thinking about this backwards.  Abstractions are in the
> upward (i.e. on the scale of low-level to high-level) direction, which
> reduces complexity for the user, but which also _increases_ complexity
> for the tools that are performing the abstraction for you.
>
> Consider a simple example at the hardware level:  If you were wanting
> to write a cos() function in assembler from scratch, on a RISC machine
> it would be a very complex set of assembler instructions, which would
> likely be fairly large in code space (at least several thousand
> instructions (in fact, on an Alpha it seems to be about 3600 bytes).
> In a CISC machine (where, interestingly, the first C stands for
> Complex), where the machine has increased its complexity so that the
> user doesn't have to deal with it, the disassembled cos function is
> more like 38 bytes, most of which is taken up in handling edge cases
> that the fcos instruction (on x87 hardware) doesn't handle.  Again,
> from the user's point of view, less complex.  From the compiler's
> point of view, more complex.
>
> So, in going the other direction, from source code to assembler/
> machine code (or, in the case of cos, from the single complex
> instruction to the thousands of instructions that would have been
> required to implement it if it weren't there), the direction from high-
> level to low level is one of increasing simplicity.  More
> instructions, yes.  But also more simplicity.  The 3600 bytes worth of
> instructions to implement cos on the alpha are all much simpler than
> the single fcos instruction on the x87.

Ok, I understand what you mean.  
A C compiler is less complex than a Lisp compiler.
An interpreter for a bytecode VM is simplier than an interpreter for CL.
And interpreting byte codes is simplier than interpreting Lisp s-exps.


> I don't buy a correlation between compressibility and simplicity any
> more than I buy a forced correlation between LOC generated and
> paycheck.  Numbers can be generated and show whatever you please, but
> there are too many factors involved to draw such a simplistic
> conclusion.

Yes, I showed only one example, statistics on a more significant
population would be needed to be able to perhaps conclude something.

-- 
__Pascal Bourguignon__
From: Paul Donnelly
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <87k530gf27.fsf@plap.localdomain>
···@informatimago.com (Pascal J. Bourguignon) writes:

> Duane Rettig <·····@franz.com> writes:
>
>> Actually, quite the opposite.  A loop is more complex than straight-
>> line code; it has a branch instruction within it, which is well-
>> understood to create pipeline stalls, unless the hardware has the
>> added complexity itself to duplicate effort in order to perform branch
>> prediction.   No, the simplest code is the fully-unrolled loop which
>> executes no branches, but which simply performs the required
>> instructions.  Is it necessarily optimal? No, because code size does
>> factor into the mix, and so the fact that loops are only unrolled
>> partially is due to tradeoffs between code complexity and instruction
>> cache size.
>
> We fight complexity with abstractions.  Which is mostly inventing new
> levels of source code generating the existing lower level of lisp, VOP
> or binary.  If adding an abstraction didn't reduce the complexity we
> wouldn't do it, we'd keep programming in assembler.

I think you two are working from two different senses of the word
“complexity”. Duane's definition in this context seems to be that
complex code is that which requires more legwork — a more involved
series of steps — for the computer to execute. Obviously interpreting
code from text or in-memory lists takes more work than running machine
code or byte code, so by this definition the process of running a
program has been simplified immensely by compilation.
From: Pascal J. Bourguignon
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <87bpobyku8.fsf@galatea.local>
Paul Donnelly <·············@sbcglobal.net> writes:

> ···@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Duane Rettig <·····@franz.com> writes:
>>
>>> Actually, quite the opposite.  A loop is more complex than straight-
>>> line code; it has a branch instruction within it, which is well-
>>> understood to create pipeline stalls, unless the hardware has the
>>> added complexity itself to duplicate effort in order to perform branch
>>> prediction.   No, the simplest code is the fully-unrolled loop which
>>> executes no branches, but which simply performs the required
>>> instructions.  Is it necessarily optimal? No, because code size does
>>> factor into the mix, and so the fact that loops are only unrolled
>>> partially is due to tradeoffs between code complexity and instruction
>>> cache size.
>>
>> We fight complexity with abstractions.  Which is mostly inventing new
>> levels of source code generating the existing lower level of lisp, VOP
>> or binary.  If adding an abstraction didn't reduce the complexity we
>> wouldn't do it, we'd keep programming in assembler.
>
> I think you two are working from two different senses of the word
> “complexity”. Duane's definition in this context seems to be that
> complex code is that which requires more legwork — a more involved
> series of steps — for the computer to execute. Obviously interpreting
> code from text or in-memory lists takes more work than running machine
> code or byte code, so by this definition the process of running a
> program has been simplified immensely by compilation.

Indeed, there's two sides of the mirror between the VM and the program
running on it.  It's not a simple interface, there's some reversed
properties.

-- 
__Pascal Bourguignon__
From: Barry Margolin
Subject: Re: Compilation Was: Is DEFCONSTANT broken?
Date: 
Message-ID: <barmar-67FA55.22145925062009@news.eternal-september.org>
In article <·················@pbourguignon.anevia.com>,
 ···@informatimago.com (Pascal J. Bourguignon) wrote:

> Duane Rettig <·····@franz.com> writes:
> 
> > The problem here is that the whole reason for
> > compilation is to reduce code complexity, and having these hooks to
> > break these simplifications goes against the goal of compilation.  
> 
> This surprize me.
> 
> I thought that the purpose of compilation was foremost to optimize
> speed.

I think it depends on what you're comparing against.  When you say 
"reason for compilation", do you mean the reason to compile instead of 
interpret, or do you mean the reason to write an a high-level language 
and compile it rather than write assembly code directly?

If it's comple vs. interpret, the reason is usually performance.

If it's compile vs. write assembly, the reason is to reduce complexity, 
improve readability, and other similar ideas.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Kaz Kylheku
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <20090705204915.242@gmail.com>
On 2009-06-23, Ron Garret <·········@flownet.com> wrote:
> In article <··················@gmail.com>,
>  Kaz Kylheku <········@gmail.com> wrote:
>
>> 
>> But seriously, how does this fare on Clozure?
>> 
>>   ;; constant definition for compile time (and source loading)
>> 
>>   (eval-when (:compile-toplevel :execute)
>>     (define-symbol-macro c7 '#.(gensym)))
>> 
>>   ;; function to return value of constant:
>>   ;; - if this is compiled, c7 is folded by macroexpansion 
>>   ;;   to return the gensym  set up by the above definition, 
>>   ;;   and that gensym is externalized into the compiled file.
>>   ;;   See CLHS 3.2.4.2.2: uninterned symbols are externalizeable, 
>>   ;;   with a similarity based on their names!!!
>>   ;; - if a compiled form of this is being loaded, then the loader will
>>   ;;   manufacture a gensym similar to the one that existed
>>   ;;   at compile time; i.e. it will create a symbol
>>   ;;   with the same name as if by MAKE-SYMBOL.
>>   ;; - if this is evaluated as source, then everything
>>   ;;   is cool; the function refers to c7, which is set
>>   ;;   up as a macro constant thanks to :execute above.
>> 
>>   (defun c7 () c7)
>> 
>>   ;; load-time constant: now that the compiled file
>>   ;; is loaded, we make c7 a synonym for the function
>>   ;; call (c7). Thus (eq c7 (c7)) is assured.
>> 
>>   (eval-when (:load-toplevel)
>>     (define-symbol-macro c7 (c7)))
>> 
>> See: two different definitions for diferent situations, creating the
>> illusion of one consistent constant.
>
> That works insofar as (eq c7 (c7)) returns T.  However, it's not really 
> what I want.  The main reason I want to use DEFCONSTANT is to prevent c7 
> from being reassigned or rebound.

The compile-time C7 expands to (QUOTE #:GENSYM). That's not an assignable
place.  So code being compiled which tries to assign to C7 will fail.

The load-time C7 expands to (C7), which is not an assignable place
either unless you program it to be (and you can  do so preemptively:
provide an expander for (c7) which signals an error).

Also, we can make the load-time c7 also expand to (quote ...).

Yes, you can rebind C7 lexically. It's not a pervasive constant. This can be
regarded as a good thing, right?  ``Global lexicals'' are hacked with symbol
macros. This is a global lexical constant.

You can redefine C7. Oh well, then you're getting a new C7 which does not
affect scopes in which the old C7 is active.

> If C7 is a symbol macro I don't get 
> that guarantee.  If I were willing to rely on the user not to assign or 
> bind c7 I could just use DEFVAR and be done with it.

But then you wouldn't get the inlining benefit of a constant.
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-BB53D2.16400823062009@news.albasani.net>
In article <··················@gmail.com>,
 Kaz Kylheku <········@gmail.com> wrote:

> On 2009-06-23, Ron Garret <·········@flownet.com> wrote:
> > In article <··················@gmail.com>,
> >  Kaz Kylheku <········@gmail.com> wrote:
> >
> >> 
> >> But seriously, how does this fare on Clozure?
> >> 
> >>   ;; constant definition for compile time (and source loading)
> >> 
> >>   (eval-when (:compile-toplevel :execute)
> >>     (define-symbol-macro c7 '#.(gensym)))
> >> 
> >>   ;; function to return value of constant:
> >>   ;; - if this is compiled, c7 is folded by macroexpansion 
> >>   ;;   to return the gensym  set up by the above definition, 
> >>   ;;   and that gensym is externalized into the compiled file.
> >>   ;;   See CLHS 3.2.4.2.2: uninterned symbols are externalizeable, 
> >>   ;;   with a similarity based on their names!!!
> >>   ;; - if a compiled form of this is being loaded, then the loader will
> >>   ;;   manufacture a gensym similar to the one that existed
> >>   ;;   at compile time; i.e. it will create a symbol
> >>   ;;   with the same name as if by MAKE-SYMBOL.
> >>   ;; - if this is evaluated as source, then everything
> >>   ;;   is cool; the function refers to c7, which is set
> >>   ;;   up as a macro constant thanks to :execute above.
> >> 
> >>   (defun c7 () c7)
> >> 
> >>   ;; load-time constant: now that the compiled file
> >>   ;; is loaded, we make c7 a synonym for the function
> >>   ;; call (c7). Thus (eq c7 (c7)) is assured.
> >> 
> >>   (eval-when (:load-toplevel)
> >>     (define-symbol-macro c7 (c7)))
> >> 
> >> See: two different definitions for diferent situations, creating the
> >> illusion of one consistent constant.
> >
> > That works insofar as (eq c7 (c7)) returns T.  However, it's not really 
> > what I want.  The main reason I want to use DEFCONSTANT is to prevent c7 
> > from being reassigned or rebound.
> 
> The compile-time C7 expands to (QUOTE #:GENSYM). That's not an assignable
> place.  So code being compiled which tries to assign to C7 will fail.
> 
> The load-time C7 expands to (C7), which is not an assignable place
> either unless you program it to be (and you can  do so preemptively:
> provide an expander for (c7) which signals an error).
> 
> Also, we can make the load-time c7 also expand to (quote ...).
> 
> Yes, you can rebind C7 lexically. It's not a pervasive constant. This can be
> regarded as a good thing, right?  ``Global lexicals'' are hacked with symbol
> macros. This is a global lexical constant.
> 
> You can redefine C7. Oh well, then you're getting a new C7 which does not
> affect scopes in which the old C7 is active.

Yeah, but that is actually a problem if someone redefines C7 and then 
tries to define a new iterator.  But that's a pretty minor problem.  
(This whole discussion is somewhat academic as I have several adequate 
workarounds already.)

> > If C7 is a symbol macro I don't get 
> > that guarantee.  If I were willing to rely on the user not to assign or 
> > bind c7 I could just use DEFVAR and be done with it.
> 
> But then you wouldn't get the inlining benefit of a constant.

I'm more concerned with correctness guarantees than efficiency.  
Premature optimization and all that.

Thanks for taking the time to respond.

rg
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-5CC259.18374422062009@news.albasani.net>
In article <··················@gmail.com>,
 Kaz Kylheku <········@gmail.com> wrote:

> On 2009-06-22, Ron Garret <·········@flownet.com> wrote:
> > In article 
> ><····································@j9g2000prh.googlegroups.com>,
> >  Scott Burson <········@gmail.com> wrote:
> >
> >> On Jun 21, 6:12 pm, Ron Garret <·········@flownet.com> wrote:
> >> >
> >> > Actually, DEFVAR comes closest to doing what I want.  But I also want to
> >> > insure that the value doesn't change or get bound.
> >> 
> >> Well, there's always DEFINE-SYMBOL-MACRO...
> >
> > Doesn't work, because it doesn't insure the value won't change:
> >
> > [···@mickey:~/Desktop]$ cat test.lisp
> >
> > (eval-when (:compile-toplevel :load-toplevel :execute)
> >
> > (define-symbol-macro c7 '#.(gensym))
> > (defun c7 () c7)
> 
> Right; you get a different instance of the c7 macro when compiling and 
> loading.
> 
> It's evaluated again, just like the initializing value of defconstant.
> 
> How about this:
> 
>   ;; macro only at compile time
>   (eval-when (:compile-toplevel)
>    (define-symbol-macro c7 '#.(gensym)))
> 
>   ;; function only available in compiled form
>   (eval-when (:load-toplevel)
>    (defun c7 () c7))
> 
> Now the problem goes away: there is /no/ C7 symbol macro when you load
> the object file.  And if you load the source file, there is no c7
> function.
> 
> Just like in C, there are no more #define constants when you're loading .o
> files. And you can't run source without compiling it. (That's not real
> programming; you're supposed to edit, compile, then run, right?)
> 
> So, everything is cool.

That won't work for me.  My actual use case is that I want to define a 
guardian value to use as an indication of an exceptional situation.  
Specifically, I want to use it in code that implements something like 
Python iterators to indicate end-of-iteration.  I also want users to be 
able to define their own iterators.  So the actual code looks something 
like this:


(defconstant +iterend+ (gensym-or-something-similar))

(defmacro iterloop (iterator)
  ... (if (eq (funcall iterator) +iterend+) (return)) ...)

(defmethod iterator ((thing class)) ... (when ... (return +iterend+)))


or something like that.  (If you want to see the actual code it's in 
http://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I 
need +iterend+ to maintain a single value in any given Lisp session.

rg
From: Lars Rune Nøstdal
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <9af29dff-e5a1-4b13-9359-459ef1c9097f@i6g2000yqj.googlegroups.com>
On Jun 23, 3:37 am, Ron Garret <·········@flownet.com> wrote:
> In article <··················@gmail.com>,
>  Kaz Kylheku <········@gmail.com> wrote:
>
>
>
>
>
> > On 2009-06-22, Ron Garret <·········@flownet.com> wrote:
> > > In article
> > ><····································@j9g2000prh.googlegroups.com>,
> > >  Scott Burson <········@gmail.com> wrote:
>
> > >> On Jun 21, 6:12 pm, Ron Garret <·········@flownet.com> wrote:
>
> > >> > Actually, DEFVAR comes closest to doing what I want.  But I also want to
> > >> > insure that the value doesn't change or get bound.
>
> > >> Well, there's always DEFINE-SYMBOL-MACRO...
>
> > > Doesn't work, because it doesn't insure the value won't change:
>
> > > [···@mickey:~/Desktop]$ cat test.lisp
>
> > > (eval-when (:compile-toplevel :load-toplevel :execute)
>
> > > (define-symbol-macro c7 '#.(gensym))
> > > (defun c7 () c7)
>
> > Right; you get a different instance of the c7 macro when compiling and
> > loading.
>
> > It's evaluated again, just like the initializing value of defconstant.
>
> > How about this:
>
> >   ;; macro only at compile time
> >   (eval-when (:compile-toplevel)
> >    (define-symbol-macro c7 '#.(gensym)))
>
> >   ;; function only available in compiled form
> >   (eval-when (:load-toplevel)
> >    (defun c7 () c7))
>
> > Now the problem goes away: there is /no/ C7 symbol macro when you load
> > the object file.  And if you load the source file, there is no c7
> > function.
>
> > Just like in C, there are no more #define constants when you're loading .o
> > files. And you can't run source without compiling it. (That's not real
> > programming; you're supposed to edit, compile, then run, right?)
>
> > So, everything is cool.
>
> That won't work for me.  My actual use case is that I want to define a
> guardian value to use as an indication of an exceptional situation.  
> Specifically, I want to use it in code that implements something like
> Python iterators to indicate end-of-iteration.  I also want users to be
> able to define their own iterators.  So the actual code looks something
> like this:
>
> (defconstant +iterend+ (gensym-or-something-similar))
>
> (defmacro iterloop (iterator)
>   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>
> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>
> or something like that.  (If you want to see the actual code it's inhttp://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I
> need +iterend+ to maintain a single value in any given Lisp session.
>
> rg


Isn't this what symbols are for? Symbols..

  ..can't be bound: *check*
  ..can't be set:   *check*

..or..


  (let (('answer 42))
    "No way.")

  (setf 'answer 42) ;; No way.


If you can't use NIL since the container might store NIL and you can't
or don't want to use two values; VALUE & FOUND-P or so, then an
unexported symbol works great, no?
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-BDCA5D.10143323062009@news.albasani.net>
In article 
<····································@i6g2000yqj.googlegroups.com>,
 Lars Rune N�stdal <···········@gmail.com> wrote:

> On Jun 23, 3:37�am, Ron Garret <·········@flownet.com> wrote:
> > In article <··················@gmail.com>,
> > �Kaz Kylheku <········@gmail.com> wrote:
> >
> >
> >
> >
> >
> > > On 2009-06-22, Ron Garret <·········@flownet.com> wrote:
> > > > In article
> > > ><····································@j9g2000prh.googlegroups.com>,
> > > > �Scott Burson <········@gmail.com> wrote:
> >
> > > >> On Jun 21, 6:12�pm, Ron Garret <·········@flownet.com> wrote:
> >
> > > >> > Actually, DEFVAR comes closest to doing what I want. �But I also 
> > > >> > want to
> > > >> > insure that the value doesn't change or get bound.
> >
> > > >> Well, there's always DEFINE-SYMBOL-MACRO...
> >
> > > > Doesn't work, because it doesn't insure the value won't change:
> >
> > > > [···@mickey:~/Desktop]$ cat test.lisp
> >
> > > > (eval-when (:compile-toplevel :load-toplevel :execute)
> >
> > > > (define-symbol-macro c7 '#.(gensym))
> > > > (defun c7 () c7)
> >
> > > Right; you get a different instance of the c7 macro when compiling and
> > > loading.
> >
> > > It's evaluated again, just like the initializing value of defconstant.
> >
> > > How about this:
> >
> > > � ;; macro only at compile time
> > > � (eval-when (:compile-toplevel)
> > > � �(define-symbol-macro c7 '#.(gensym)))
> >
> > > � ;; function only available in compiled form
> > > � (eval-when (:load-toplevel)
> > > � �(defun c7 () c7))
> >
> > > Now the problem goes away: there is /no/ C7 symbol macro when you load
> > > the object file. �And if you load the source file, there is no c7
> > > function.
> >
> > > Just like in C, there are no more #define constants when you're loading 
> > > .o
> > > files. And you can't run source without compiling it. (That's not real
> > > programming; you're supposed to edit, compile, then run, right?)
> >
> > > So, everything is cool.
> >
> > That won't work for me. �My actual use case is that I want to define a
> > guardian value to use as an indication of an exceptional situation. �
> > Specifically, I want to use it in code that implements something like
> > Python iterators to indicate end-of-iteration. �I also want users to be
> > able to define their own iterators. �So the actual code looks something
> > like this:
> >
> > (defconstant +iterend+ (gensym-or-something-similar))
> >
> > (defmacro iterloop (iterator)
> > � ... (if (eq (funcall iterator) +iterend+) (return)) ...)
> >
> > (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
> >
> > or something like that. �(If you want to see the actual code it's 
> > inhttp://www.flownet.com/ron/lisp/rg-utils.lisp). �But the point is that I
> > need +iterend+ to maintain a single value in any given Lisp session.
> >
> > rg
> 
> 
> Isn't this what symbols are for? Symbols..
> 
>   ..can't be bound: *check*
>   ..can't be set:   *check*
> 
> ..or..
> 
> 
>   (let (('answer 42))
>     "No way.")
> 
>   (setf 'answer 42) ;; No way.
> 
> 
> If you can't use NIL since the container might store NIL and you can't
> or don't want to use two values; VALUE & FOUND-P or so, then an
> unexported symbol works great, no?

Normally yes.  However, the application here is special: this value is 
being used to indicate an exceptional situation (the motivating example 
is the end of an iteration) and so it's important that this value be 
available *only* through the facility that generates the exceptional 
situation and not any other way.  So yes, you can use a symbol, but it 
can't be an interned symbol or you might accidentally generate it 
through a call to READ or INTERN.  So it has to be an uninterned symbol.  
But then to use it you have to bind it to something precisely because 
you can't generate it any other way.  And then you want to make sure 
that that binding never changes.

rg
From: Lars Rune Nøstdal
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <56cff9fc-3151-44b7-b296-7b050d5d18ea@x5g2000yqk.googlegroups.com>
On Jun 23, 7:14 pm, Ron Garret <·········@flownet.com> wrote:
> In article
> <····································@i6g2000yqj.googlegroups.com>,
>  Lars Rune Nøstdal <···········@gmail.com> wrote:
>
>
>
>
>
> > On Jun 23, 3:37 am, Ron Garret <·········@flownet.com> wrote:
> > > In article <··················@gmail.com>,
> > >  Kaz Kylheku <········@gmail.com> wrote:
>
> > > > On 2009-06-22, Ron Garret <·········@flownet.com> wrote:
> > > > > In article
> > > > ><····································@j9g2000prh.googlegroups.com>,
> > > > >  Scott Burson <········@gmail.com> wrote:
>
> > > > >> On Jun 21, 6:12 pm, Ron Garret <·········@flownet.com> wrote:
>
> > > > >> > Actually, DEFVAR comes closest to doing what I want.  But I also
> > > > >> > want to
> > > > >> > insure that the value doesn't change or get bound.
>
> > > > >> Well, there's always DEFINE-SYMBOL-MACRO...
>
> > > > > Doesn't work, because it doesn't insure the value won't change:
>
> > > > > [···@mickey:~/Desktop]$ cat test.lisp
>
> > > > > (eval-when (:compile-toplevel :load-toplevel :execute)
>
> > > > > (define-symbol-macro c7 '#.(gensym))
> > > > > (defun c7 () c7)
>
> > > > Right; you get a different instance of the c7 macro when compiling and
> > > > loading.
>
> > > > It's evaluated again, just like the initializing value of defconstant.
>
> > > > How about this:
>
> > > >   ;; macro only at compile time
> > > >   (eval-when (:compile-toplevel)
> > > >    (define-symbol-macro c7 '#.(gensym)))
>
> > > >   ;; function only available in compiled form
> > > >   (eval-when (:load-toplevel)
> > > >    (defun c7 () c7))
>
> > > > Now the problem goes away: there is /no/ C7 symbol macro when you load
> > > > the object file.  And if you load the source file, there is no c7
> > > > function.
>
> > > > Just like in C, there are no more #define constants when you're loading
> > > > .o
> > > > files. And you can't run source without compiling it. (That's not real
> > > > programming; you're supposed to edit, compile, then run, right?)
>
> > > > So, everything is cool.
>
> > > That won't work for me.  My actual use case is that I want to define a
> > > guardian value to use as an indication of an exceptional situation.  
> > > Specifically, I want to use it in code that implements something like
> > > Python iterators to indicate end-of-iteration.  I also want users to be
> > > able to define their own iterators.  So the actual code looks something
> > > like this:
>
> > > (defconstant +iterend+ (gensym-or-something-similar))
>
> > > (defmacro iterloop (iterator)
> > >   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>
> > > (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>
> > > or something like that.  (If you want to see the actual code it's
> > > inhttp://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I
> > > need +iterend+ to maintain a single value in any given Lisp session.
>
> > > rg
>
> > Isn't this what symbols are for? Symbols..
>
> >   ..can't be bound: *check*
> >   ..can't be set:   *check*
>
> > ..or..
>
> >   (let (('answer 42))
> >     "No way.")
>
> >   (setf 'answer 42) ;; No way.
>
> > If you can't use NIL since the container might store NIL and you can't
> > or don't want to use two values; VALUE & FOUND-P or so, then an
> > unexported symbol works great, no?
>
> Normally yes.  However, the application here is special: this value is
> being used to indicate an exceptional situation (the motivating example
> is the end of an iteration) and so it's important that this value be
> available *only* through the facility that generates the exceptional
> situation and not any other way.  So yes, you can use a symbol, but it
> can't be an interned symbol or you might accidentally generate it
> through a call to READ or INTERN.  So it has to be an uninterned symbol.  
> But then to use it you have to bind it

But if you've bound the unique thingy to a symbol -- people can still
access that unique thingy via that symbol, by mistake?


;; We'll pretend you have your DEFCONSTANTTHATACTUALLYWORKS here:
CL-USER> (defparameter +iterend+ (gensym))
+ITEREND+

;; But still:
CL-USER> (let ((x (symbol-value (read-from-string "+iterend+")))
               (list (list "you'll" "never" "see" "us" "haaha")))
           (push x list)
           (push "is this all?" list)
           (dolist (elt list)
             (when (eq elt +iterend+)
               (return))
             (format t "~A " elt))
           (terpri))
is this all?
NIL
CL-USER>


..no?

Wait, no ... no, uh, of _course_ you are _not_ passing end-user input
directly to READ(-FROM-STRING) and/or INTERN, rite?

..so why the paranoia? Maybe you need to read Naggums posts about C++,
paranoia, liars etc. :}



> to something precisely because
> you can't generate it any other way.  And then you want to make sure
> that that binding never changes.
>
> rg
From: Thomas F. Burdick
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <b75fdb8a-6682-4954-b91e-8a087b81069c@k38g2000yqh.googlegroups.com>
On Jun 23, 7:14 pm, Ron Garret <·········@flownet.com> wrote:
> In article
> <····································@i6g2000yqj.googlegroups.com>,
>  Lars Rune Nøstdal <···········@gmail.com> wrote:
>
>
>
>
>
> > On Jun 23, 3:37 am, Ron Garret <·········@flownet.com> wrote:
> > > In article <··················@gmail.com>,
> > >  Kaz Kylheku <········@gmail.com> wrote:
>
> > > > On 2009-06-22, Ron Garret <·········@flownet.com> wrote:
> > > > > In article
> > > > ><····································@j9g2000prh.googlegroups.com>,
> > > > >  Scott Burson <········@gmail.com> wrote:
>
> > > > >> On Jun 21, 6:12 pm, Ron Garret <·········@flownet.com> wrote:
>
> > > > >> > Actually, DEFVAR comes closest to doing what I want.  But I also
> > > > >> > want to
> > > > >> > insure that the value doesn't change or get bound.
>
> > > > >> Well, there's always DEFINE-SYMBOL-MACRO...
>
> > > > > Doesn't work, because it doesn't insure the value won't change:
>
> > > > > [···@mickey:~/Desktop]$ cat test.lisp
>
> > > > > (eval-when (:compile-toplevel :load-toplevel :execute)
>
> > > > > (define-symbol-macro c7 '#.(gensym))
> > > > > (defun c7 () c7)
>
> > > > Right; you get a different instance of the c7 macro when compiling and
> > > > loading.
>
> > > > It's evaluated again, just like the initializing value of defconstant.
>
> > > > How about this:
>
> > > >   ;; macro only at compile time
> > > >   (eval-when (:compile-toplevel)
> > > >    (define-symbol-macro c7 '#.(gensym)))
>
> > > >   ;; function only available in compiled form
> > > >   (eval-when (:load-toplevel)
> > > >    (defun c7 () c7))
>
> > > > Now the problem goes away: there is /no/ C7 symbol macro when you load
> > > > the object file.  And if you load the source file, there is no c7
> > > > function.
>
> > > > Just like in C, there are no more #define constants when you're loading
> > > > .o
> > > > files. And you can't run source without compiling it. (That's not real
> > > > programming; you're supposed to edit, compile, then run, right?)
>
> > > > So, everything is cool.
>
> > > That won't work for me.  My actual use case is that I want to define a
> > > guardian value to use as an indication of an exceptional situation.  
> > > Specifically, I want to use it in code that implements something like
> > > Python iterators to indicate end-of-iteration.  I also want users to be
> > > able to define their own iterators.  So the actual code looks something
> > > like this:
>
> > > (defconstant +iterend+ (gensym-or-something-similar))
>
> > > (defmacro iterloop (iterator)
> > >   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>
> > > (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>
> > > or something like that.  (If you want to see the actual code it's
> > > inhttp://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I
> > > need +iterend+ to maintain a single value in any given Lisp session.
>
> > > rg
>
> > Isn't this what symbols are for? Symbols..
>
> >   ..can't be bound: *check*
> >   ..can't be set:   *check*
>
> > ..or..
>
> >   (let (('answer 42))
> >     "No way.")
>
> >   (setf 'answer 42) ;; No way.
>
> > If you can't use NIL since the container might store NIL and you can't
> > or don't want to use two values; VALUE & FOUND-P or so, then an
> > unexported symbol works great, no?
>
> Normally yes.  However, the application here is special: this value is
> being used to indicate an exceptional situation (the motivating example
> is the end of an iteration) and so it's important that this value be
> available *only* through the facility that generates the exceptional
> situation and not any other way.  So yes, you can use a symbol, but it
> can't be an interned symbol or you might accidentally generate it
> through a call to READ or INTERN.  So it has to be an uninterned symbol.  
> But then to use it you have to bind it to something precisely because
> you can't generate it any other way.  And then you want to make sure
> that that binding never changes.

Of course, you can still accidentally generate it with a call to
INTERN and another to SYMBOL-VALUE. Less likely, of course, but I'm
not so sure that something like my-package::|| private do not use this
symbol name -- magical iterator stop value -- seriously, DON'T USE
THIS AS A VARIABLE OR VALUE !!!1!|| would be qualitatively worse.
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-CE81E0.17010823062009@news.albasani.net>
In article 
<····································@k38g2000yqh.googlegroups.com>,
 "Thomas F. Burdick" <········@gmail.com> wrote:

> On Jun 23, 7:14�pm, Ron Garret <·········@flownet.com> wrote:
> > In article
> > <····································@i6g2000yqj.googlegroups.com>,
> > �Lars Rune N�stdal <···········@gmail.com> wrote:
> >
> >
> >
> >
> >
> > > On Jun 23, 3:37�am, Ron Garret <·········@flownet.com> wrote:
> > > > In article <··················@gmail.com>,
> > > > �Kaz Kylheku <········@gmail.com> wrote:
> >
> > > > > On 2009-06-22, Ron Garret <·········@flownet.com> wrote:
> > > > > > In article
> > > > > ><····································@j9g2000prh.googlegroups.com>,
> > > > > > �Scott Burson <········@gmail.com> wrote:
> >
> > > > > >> On Jun 21, 6:12�pm, Ron Garret <·········@flownet.com> wrote:
> >
> > > > > >> > Actually, DEFVAR comes closest to doing what I want. �But I also
> > > > > >> > want to
> > > > > >> > insure that the value doesn't change or get bound.
> >
> > > > > >> Well, there's always DEFINE-SYMBOL-MACRO...
> >
> > > > > > Doesn't work, because it doesn't insure the value won't change:
> >
> > > > > > [···@mickey:~/Desktop]$ cat test.lisp
> >
> > > > > > (eval-when (:compile-toplevel :load-toplevel :execute)
> >
> > > > > > (define-symbol-macro c7 '#.(gensym))
> > > > > > (defun c7 () c7)
> >
> > > > > Right; you get a different instance of the c7 macro when compiling 
> > > > > and
> > > > > loading.
> >
> > > > > It's evaluated again, just like the initializing value of 
> > > > > defconstant.
> >
> > > > > How about this:
> >
> > > > > � ;; macro only at compile time
> > > > > � (eval-when (:compile-toplevel)
> > > > > � �(define-symbol-macro c7 '#.(gensym)))
> >
> > > > > � ;; function only available in compiled form
> > > > > � (eval-when (:load-toplevel)
> > > > > � �(defun c7 () c7))
> >
> > > > > Now the problem goes away: there is /no/ C7 symbol macro when you 
> > > > > load
> > > > > the object file. �And if you load the source file, there is no c7
> > > > > function.
> >
> > > > > Just like in C, there are no more #define constants when you're 
> > > > > loading
> > > > > .o
> > > > > files. And you can't run source without compiling it. (That's not 
> > > > > real
> > > > > programming; you're supposed to edit, compile, then run, right?)
> >
> > > > > So, everything is cool.
> >
> > > > That won't work for me. �My actual use case is that I want to define a
> > > > guardian value to use as an indication of an exceptional situation. �
> > > > Specifically, I want to use it in code that implements something like
> > > > Python iterators to indicate end-of-iteration. �I also want users to be
> > > > able to define their own iterators. �So the actual code looks something
> > > > like this:
> >
> > > > (defconstant +iterend+ (gensym-or-something-similar))
> >
> > > > (defmacro iterloop (iterator)
> > > > � ... (if (eq (funcall iterator) +iterend+) (return)) ...)
> >
> > > > (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
> >
> > > > or something like that. �(If you want to see the actual code it's
> > > > inhttp://www.flownet.com/ron/lisp/rg-utils.lisp). �But the point is 
> > > > that I
> > > > need +iterend+ to maintain a single value in any given Lisp session.
> >
> > > > rg
> >
> > > Isn't this what symbols are for? Symbols..
> >
> > > � ..can't be bound: *check*
> > > � ..can't be set: � *check*
> >
> > > ..or..
> >
> > > � (let (('answer 42))
> > > � � "No way.")
> >
> > > � (setf 'answer 42) ;; No way.
> >
> > > If you can't use NIL since the container might store NIL and you can't
> > > or don't want to use two values; VALUE & FOUND-P or so, then an
> > > unexported symbol works great, no?
> >
> > Normally yes. �However, the application here is special: this value is
> > being used to indicate an exceptional situation (the motivating example
> > is the end of an iteration) and so it's important that this value be
> > available *only* through the facility that generates the exceptional
> > situation and not any other way. �So yes, you can use a symbol, but it
> > can't be an interned symbol or you might accidentally generate it
> > through a call to READ or INTERN. �So it has to be an uninterned symbol. �
> > But then to use it you have to bind it to something precisely because
> > you can't generate it any other way. �And then you want to make sure
> > that that binding never changes.
> 
> Of course, you can still accidentally generate it with a call to
> INTERN and another to SYMBOL-VALUE. Less likely, of course, but I'm
> not so sure that something like my-package::|| private do not use this
> symbol name -- magical iterator stop value -- seriously, DON'T USE
> THIS AS A VARIABLE OR VALUE !!!1!|| would be qualitatively worse.

A good point.  I think Kaz's suggestion of using multiple values is 
probably the Right Answer.

rg
From: Pascal J. Bourguignon
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <7czlbzpcsv.fsf@pbourguignon.anevia.com>
Ron Garret <·········@flownet.com> writes:
> That won't work for me.  My actual use case is that I want to define a 
> guardian value to use as an indication of an exceptional situation.  
> Specifically, I want to use it in code that implements something like 
> Python iterators to indicate end-of-iteration.  I also want users to be 
> able to define their own iterators.  So the actual code looks something 
> like this:
>
>
> (defconstant +iterend+ (gensym-or-something-similar))
>
> (defmacro iterloop (iterator)
>   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>
> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>
>
> or something like that.  (If you want to see the actual code it's in 
> http://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I 
> need +iterend+ to maintain a single value in any given Lisp session.

And why don't you use NIL?  NIL is the designated end in lisp...

-- 
__Pascal Bourguignon__
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-AD7F3B.10161323062009@news.albasani.net>
In article <··············@pbourguignon.anevia.com>,
 ···@informatimago.com (Pascal J. Bourguignon) wrote:

> Ron Garret <·········@flownet.com> writes:
> > That won't work for me.  My actual use case is that I want to define a 
> > guardian value to use as an indication of an exceptional situation.  
> > Specifically, I want to use it in code that implements something like 
> > Python iterators to indicate end-of-iteration.  I also want users to be 
> > able to define their own iterators.  So the actual code looks something 
> > like this:
> >
> >
> > (defconstant +iterend+ (gensym-or-something-similar))
> >
> > (defmacro iterloop (iterator)
> >   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
> >
> > (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
> >
> >
> > or something like that.  (If you want to see the actual code it's in 
> > http://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I 
> > need +iterend+ to maintain a single value in any given Lisp session.
> 
> And why don't you use NIL?  NIL is the designated end in lisp...

Because NIL can (and often is) generated as one of the constituent 
values of an abstract sequence.  If I used NIL as the end-of-iteration 
market then the iteration would end at the occurrence of the first NIL 
rather than the end of the sequence.

rg
From: Kaz Kylheku
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <20090705182649.997@gmail.com>
On 2009-06-23, Ron Garret <·········@flownet.com> wrote:
> Because NIL can (and often is) generated as one of the constituent 
> values of an abstract sequence.  If I used NIL as the end-of-iteration 
> market then the iteration would end at the occurrence of the first NIL 
> rather than the end of the sequence.

But note that, for instance, a set of multiple values cannot be an element of a
sequence.
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-26063F.16595023062009@news.albasani.net>
In article <··················@gmail.com>,
 Kaz Kylheku <········@gmail.com> wrote:

> On 2009-06-23, Ron Garret <·········@flownet.com> wrote:
> > Because NIL can (and often is) generated as one of the constituent 
> > values of an abstract sequence.  If I used NIL as the end-of-iteration 
> > market then the iteration would end at the occurrence of the first NIL 
> > rather than the end of the sequence.
> 
> But note that, for instance, a set of multiple values cannot be an element of 
> a sequence.

A very good point.  Multiple values are probably the Right Answer in 
this case.

rg
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-FC0D85.10181523062009@news.albasani.net>
In article <··············@wyoming.home>,
 Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) wrote:

> ···@informatimago.com (Pascal J. Bourguignon) writes:
> 
> > Ron Garret <·········@flownet.com> writes:
> >> That won't work for me.  My actual use case is that I want to define a 
> >> guardian value to use as an indication of an exceptional situation.  
> >> Specifically, I want to use it in code that implements something like 
> >> Python iterators to indicate end-of-iteration.  I also want users to be 
> >> able to define their own iterators.  So the actual code looks something 
> >> like this:
> >>
> >>
> >> (defconstant +iterend+ (gensym-or-something-similar))
> >>
> >> (defmacro iterloop (iterator)
> >>   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
> >>
> >> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
> >>
> >>
> >> or something like that.  (If you want to see the actual code it's in 
> >> http://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I 
> >> need +iterend+ to maintain a single value in any given Lisp session.
> >
> > And why don't you use NIL?  NIL is the designated end in lisp...
> 
> Because NIL is obviously a possible value produced by the iterator.
> But why use a magic value at all?  You want Python-like behaviour, do
> what Python does: have it throw/signal when it hits the end...

That's a good question.  I had a reason for doing it this way back when 
I started but I can no longer remember what it was.  (Efficiency maybe?)  
Maybe I should go back and revisit that decision.

rg
From: Barry Fishman
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <m3my7z2c6h.fsf@barry_fishman.acm.org>
Ron Garret <·········@flownet.com> writes:
> That won't work for me.  My actual use case is that I want to define a 
> guardian value to use as an indication of an exceptional situation.  
> Specifically, I want to use it in code that implements something like 
> Python iterators to indicate end-of-iteration.  I also want users to be 
> able to define their own iterators.  So the actual code looks something 
> like this:
>
>
> (defconstant +iterend+ (gensym-or-something-similar))
>
> (defmacro iterloop (iterator)
>   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>
> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>
>
> or something like that.  (If you want to see the actual code it's in 
> http://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I 
> need +iterend+ to maintain a single value in any given Lisp session.

I suspect you don't need something to be constant, just something unique.

Couldn't you just use a function (or two)?

(let ((v (gensym)))
  (defun iter-end ()
    v)
  (defun iter-endp (val)
    (eq v val)))

-- 
Barry Fishman
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-AF0F1F.10014023062009@news.albasani.net>
In article <··············@barry_fishman.acm.org>,
 Barry Fishman <·············@acm.org> wrote:

> Ron Garret <·········@flownet.com> writes:
> > That won't work for me.  My actual use case is that I want to define a 
> > guardian value to use as an indication of an exceptional situation.  
> > Specifically, I want to use it in code that implements something like 
> > Python iterators to indicate end-of-iteration.  I also want users to be 
> > able to define their own iterators.  So the actual code looks something 
> > like this:
> >
> >
> > (defconstant +iterend+ (gensym-or-something-similar))
> >
> > (defmacro iterloop (iterator)
> >   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
> >
> > (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
> >
> >
> > or something like that.  (If you want to see the actual code it's in 
> > http://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I 
> > need +iterend+ to maintain a single value in any given Lisp session.
> 
> I suspect you don't need something to be constant, just something unique.
> 
> Couldn't you just use a function (or two)?
> 
> (let ((v (gensym)))
>   (defun iter-end ()
>     v)
>   (defun iter-endp (val)
>     (eq v val)))

Yes, that would probably work.  I bring up the original application not 
so much because I can't get it to work (for the time being I'm just 
using an interned symbol with a very obscure name) but because it 
provides a motivation for the underlying question.

There's actually a related question that just occurred to me: what is 
the design rationale behind DEFCONSTANT, and in particular, what is the 
advantage of giving it the latitude that it has to re-evaluate its 
initialization form separately at both compile time and run time?  What 
does that latitude buy you?

rg
From: Pascal J. Bourguignon
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <7c1vpbp36s.fsf@pbourguignon.anevia.com>
Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) writes:

> ···@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Ron Garret <·········@flownet.com> writes:
>>> That won't work for me.  My actual use case is that I want to define a 
>>> guardian value to use as an indication of an exceptional situation.  
>>> Specifically, I want to use it in code that implements something like 
>>> Python iterators to indicate end-of-iteration.  I also want users to be 
>>> able to define their own iterators.  So the actual code looks something 
>>> like this:
>>>
>>>
>>> (defconstant +iterend+ (gensym-or-something-similar))
>>>
>>> (defmacro iterloop (iterator)
>>>   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>>>
>>> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>>>
>>>
>>> or something like that.  (If you want to see the actual code it's in 
>>> http://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I 
>>> need +iterend+ to maintain a single value in any given Lisp session.
>>
>> And why don't you use NIL?  NIL is the designated end in lisp...
>
> Because NIL is obviously a possible value produced by the iterator.
> But why use a magic value at all?  You want [COMMON-LISP]-like behaviour, do
> what [COMMON-LISP] does: have it [signal an error] when it hits the end...

See for example READ, READ-CHAR, READ-LINE, READ-SEQUENCE.

-- 
__Pascal Bourguignon__
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-205B74.10185123062009@news.albasani.net>
In article <··············@wyoming.home>,
 Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) wrote:

> ···@informatimago.com (Pascal J. Bourguignon) writes:
> 
> > Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) writes:
> >
> >> ···@informatimago.com (Pascal J. Bourguignon) writes:
> >>
> >>> Ron Garret <·········@flownet.com> writes:
> >>>> That won't work for me.  My actual use case is that I want to define a 
> >>>> guardian value to use as an indication of an exceptional situation.  
> >>>> Specifically, I want to use it in code that implements something like 
> >>>> Python iterators to indicate end-of-iteration.  I also want users to be 
> >>>> able to define their own iterators.  So the actual code looks something 
> >>>> like this:
> >>>>
> >>>>
> >>>> (defconstant +iterend+ (gensym-or-something-similar))
> >>>>
> >>>> (defmacro iterloop (iterator)
> >>>>   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
> >>>>
> >>>> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
> >>>>
> >>>>
> >>>> or something like that.  (If you want to see the actual code it's in 
> >>>> http://www.flownet.com/ron/lisp/rg-utils.lisp).
> 
> [Warning to others: don't make the same mistake I did and look at this.
> I almost vomited over my keyboard...still feel a bit queasy]

Thank you for that constructive criticism.

rg
From: Kaz Kylheku
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <20090705210033.637@gmail.com>
On 2009-06-23, Paul Foley <···@below.invalid> wrote:
> ···@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) writes:
>>
>>> ···@informatimago.com (Pascal J. Bourguignon) writes:
>>>> And why don't you use NIL?  NIL is the designated end in lisp...
>>>
>>> Because NIL is obviously a possible value produced by the iterator.
>>> But why use a magic value at all?  You want [COMMON-LISP]-like behaviour, do
>>> what [COMMON-LISP] does: have it [signal an error] when it hits the end...
>>
>> See for example READ, READ-CHAR, READ-LINE, READ-SEQUENCE.
>
> I'd use THROW for what Ron wants to do, though.

Throw does not eliminate the need for a magic value. THROW is just a
long-distance version of RETURN-FROM. It finds a matching catch and terminates
that form, using the return value specified in the THROW.  So now the ambiguity
problem emanates from the CATCH. Did the form evaluated under CATCH return NIL
normally? Or was the NIL thrown?

One thing an iterator function can do to indicate ``there are no more items''
in a way that allows NIL to be an item, is to return two values:

  (defparameter *iter* (make-list-iterator '(1 2 3 nil))

  (get-next *iter*) -> 1 ; T
  (get-next *iter*) -> 2 ; T
  (get-next *iter*) -> 3 ; T
  (get-next *iter*) -> NIL ; T
  (get-next *iter*) -> NIL ; NIL

This is how GETHASH disambiguates the situation of NIL being positively
associated with a key, versus NIL meaning ``key not found''.

You know, you could even set a flag in the iterator object. 

When the get-next operation returns nil, you could have a predicate which
tests the flag:

  (when (and (null (get-next *iter*))
             (iter-done *iter*))
    ;; we are done iterating
    )

This iter-done flag is set if there is an unsuccessful attempt
to extract another item.
From: http://public.xdi.org/=pf
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <m2y6rie9tq.fsf@wyoming.home>
Kaz Kylheku <········@gmail.com> writes:

> On 2009-06-23, Paul Foley <···@below.invalid> wrote:
>> ···@informatimago.com (Pascal J. Bourguignon) writes:
>>
>>> Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) writes:
>>>
>>>> ···@informatimago.com (Pascal J. Bourguignon) writes:
>>>>> And why don't you use NIL?  NIL is the designated end in lisp...
>>>>
>>>> Because NIL is obviously a possible value produced by the iterator.
>>>> But why use a magic value at all?  You want [COMMON-LISP]-like behaviour, do
>>>> what [COMMON-LISP] does: have it [signal an error] when it hits the end...
>>>
>>> See for example READ, READ-CHAR, READ-LINE, READ-SEQUENCE.
>>
>> I'd use THROW for what Ron wants to do, though.
>
> Throw does not eliminate the need for a magic value. THROW is just a
> long-distance version of RETURN-FROM. It finds a matching catch and terminates
> that form, using the return value specified in the THROW.

Yes - which is exactly what you want.  Altering your code:

(defmacro for (var in thing &body body)
  (unless (sym= in :in) (warn "expected keyword 'in', got ~A instead" in))
  (with-gensym itervar
    `(catch 'iteration-complete
       (let ( (,itervar (iterator ,thing)) )
         ,(if (consp var)
            `(loop for ,var = (multiple-value-list (funcall ,itervar))
               ,@body)
            `(loop for ,var = (funcall ,itervar)
               ,@body))))))
From: Scott Burson
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <02d09e17-2bb7-401c-82c0-6199f7336a65@g15g2000pra.googlegroups.com>
On Jun 22, 6:37 pm, Ron Garret <·········@flownet.com> wrote:
>
> That won't work for me.  My actual use case is that I want to define a
> guardian value to use as an indication of an exceptional situation.  
> Specifically, I want to use it in code that implements something like
> Python iterators to indicate end-of-iteration.  I also want users to be
> able to define their own iterators.  So the actual code looks something
> like this:
>
> (defconstant +iterend+ (gensym-or-something-similar))
>
> (defmacro iterloop (iterator)
>   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>
> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>
> or something like that.  (If you want to see the actual code it's inhttp://www.flownet.com/ron/lisp/rg-utils.lisp).  But the point is that I
> need +iterend+ to maintain a single value in any given Lisp session.

FWIW, in similar situations I have done things like

(defconstant +iterend+ '|~.&·@ truly unlikely symbol name @+&.~|)

This isn't quite as evil as it looks because I'm certainly not going
to export that symbol.

-- Scott
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-5F0839.16423323062009@news.albasani.net>
In article 
<····································@g15g2000pra.googlegroups.com>,
 Scott Burson <········@gmail.com> wrote:

> On Jun 22, 6:37�pm, Ron Garret <·········@flownet.com> wrote:
> >
> > That won't work for me. �My actual use case is that I want to define a
> > guardian value to use as an indication of an exceptional situation. �
> > Specifically, I want to use it in code that implements something like
> > Python iterators to indicate end-of-iteration. �I also want users to be
> > able to define their own iterators. �So the actual code looks something
> > like this:
> >
> > (defconstant +iterend+ (gensym-or-something-similar))
> >
> > (defmacro iterloop (iterator)
> > � ... (if (eq (funcall iterator) +iterend+) (return)) ...)
> >
> > (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
> >
> > or something like that. �(If you want to see the actual code it's 
> > inhttp://www.flownet.com/ron/lisp/rg-utils.lisp). �But the point is that I
> > need +iterend+ to maintain a single value in any given Lisp session.
> 
> FWIW, in similar situations I have done things like
> 
> (defconstant +iterend+ '|~.&·@ truly unlikely symbol name @+&.~|)
> 
> This isn't quite as evil as it looks because I'm certainly not going
> to export that symbol.
> 
> -- Scott

Yes, that's actually the solution I've settled on for the moment.  I 
chose a symbol with a couple of #\# characters in its name.

rg
From: Pascal J. Bourguignon
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <7cmy7znjab.fsf@pbourguignon.anevia.com>
Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) writes:

> ···@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) writes:
>>
>>> ···@informatimago.com (Pascal J. Bourguignon) writes:
>>>
>>>> Ron Garret <·········@flownet.com> writes:
>>>>> That won't work for me.  My actual use case is that I want to define a 
>>>>> guardian value to use as an indication of an exceptional situation.  
>>>>> Specifically, I want to use it in code that implements something like 
>>>>> Python iterators to indicate end-of-iteration.  I also want users to be 
>>>>> able to define their own iterators.  So the actual code looks something 
>>>>> like this:
>>>>>
>>>>>
>>>>> (defconstant +iterend+ (gensym-or-something-similar))
>>>>>
>>>>> (defmacro iterloop (iterator)
>>>>>   ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>>>>>
>>>>> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>>>>>
>>>>>
>>>>> or something like that.  (If you want to see the actual code it's in 
>>>>> http://www.flownet.com/ron/lisp/rg-utils.lisp).
>
> [Warning to others: don't make the same mistake I did and look at this.
> I almost vomited over my keyboard...still feel a bit queasy]
>
>>>>>                                                 But the point is that I 
>>>>> need +iterend+ to maintain a single value in any given Lisp session.
>>>>
>>>> And why don't you use NIL?  NIL is the designated end in lisp...
>>>
>>> Because NIL is obviously a possible value produced by the iterator.
>>> But why use a magic value at all?  You want [COMMON-LISP]-like behaviour, do
>>> what [COMMON-LISP] does: have it [signal an error] when it hits the end...
>>
>> See for example READ, READ-CHAR, READ-LINE, READ-SEQUENCE.
>
> I'd use THROW for what Ron wants to do, though.

Why?  These functions establish a good pattern to deal with the end of
an input stream, and iterators certainly can be considered as streams.
Moreover, they are quite versatile, with their eof-error-p and
eof-value parameters.

(handler-case (loop (iterator-next it :eof-error-p t))
  (end-of-iteration (err) (princ 'done)))

(loop
    :while (iterator-next it :eof-error-p nil))
                            ; I know I don't have nils in it.

(loop
    :until (eq it (iterator-next it :eof-error-p nil :eof-value it))) 
                               ; or any other user supplied eof-value.


-- 
__Pascal Bourguignon__
From: Lars Rune Nøstdal
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <de9fa4b5-c177-461b-96d5-d87f48a39f82@n4g2000vba.googlegroups.com>
On Jun 22, 3:12 am, Ron Garret <·········@flownet.com> wrote:
> In article <··············@galatea.local>,
>  ····@informatimago.com (Pascal J. Bourguignon) wrote:
>
>
>
>
>
> > Ron Garret <·········@flownet.com> writes:
>
> > > In article <··············@galatea.local>,
> > >  ····@informatimago.com (Pascal J. Bourguignon) wrote:
>
> > >> Ron Garret <·········@flownet.com> writes:
>
> > >> > Consider the following code:
>
> > >> > (eval-when (:load-toplevel :compile-toplevel :execute)
>
> > >> >   (defconstant foo ...)
>
> > >> >   (defun foo () foo)
>
> > >> > )
>
> > >> > Are there any circumstances under which, in an ANSI-compliant
> > >> > implementation of CL, (equal foo (foo)) can return NIL?
>
> > >> Indeed, but not in conforming code.
>
> > >>     A constant defined by defconstant can be redefined with
> > >>     defconstant. However, the consequences are undefined if an attempt
> > >>     [...]
> > >>     to assign it to a different value using a subsequent defconstant.
>
> > > That's true.  But there are legitimate use-cases where this is quite
> > > difficult for the user to achieve.  The particular use-case I'm thinking
> > > of (the one that brought this issue to my attention) is creating a
> > > guardian, that is, a singleton that is used as a distinguished value to
> > > indicate some kind of exceptional condition.  The way I was taught to do
> > > that is with a gensym, but as you can see that can lead to difficulties.
>
> > There should be no difficulty, as long as you don't try to compare the
> > values that should be EQL but are not, across different times.  And
> > you would have to do some special things to do so.  For example:
>
> >     (defconstant +x+ (gensym))
>
> >     (defun f (x)
> >       (case x
> >         ((#.+x+) :fails-across-compile/load)))
>
> > Anyways, the advice is to use defconstant only on values of type
> > number, character or (interned) symbol.
>
> The problem can be exhibited (as I show below) with any non-idempotent
> function, including for example, get-internal-real-time.  So restricting
> yourself to numbers doesn't help.
>
> > >> > It turns out that there are.  I'll describe what those circumstances are
> > >> > in a moment (makes a good exercise to figure it out on your own).  The
> > >> > question I want to raise is, given that this is the case, is this aspect
> > >> > of DEFCONSTANT's behavior so at odds with intuition that it can be
> > >> > considered broken?  And if so, what, if anything, should be done about
> > >> > it?
>
> > >> Yes, in a way we may consider defconstant to be broken.  What can be
> > >> done, is avoid using it.
>
> > > Would that be what you recommend?
>
> > Avoid using DEFCONSTANT.  Try DEFPARAMETER, it works better.
>
> Actually, DEFVAR comes closest to doing what I want.  But I also want to
> insure that the value doesn't change or get bound.

SBCL has SB-EXT:DEFGLOBAL which might be at least one step closer to
what you're after. It's similar to CL:DEFVAR, but does not allow
rebinding of the variable:
  http://www.sbcl.org/manual/Global-and-Always_002dBound-variables.html

(sb-ext:defglobal -answer- 42)

(let ((-answer- 43))
  (pprint -answer-))
;; ## "The name of the lambda variable -ANSWER- is already in use to
name
;; a global variable."
From: D Herring
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <4a3f1816$0$29136$6e1ede2f@read.cnntp.org>
Ron Garret wrote:
> Consider the following code:
> 
> (eval-when (:load-toplevel :compile-toplevel :execute)
> 
>   (defconstant foo ...)
> 
>   (defun foo () foo)
> 
> )
> 
> Are there any circumstances under which, in an ANSI-compliant 
> implementation of CL, (equal foo (foo)) can return NIL?
...
> Discuss.

I like SBCL's take on this.
http://www.sbcl.org/manual/Defining-Constants.html

- Daniel
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-B653D4.23154621062009@news.albasani.net>
In article <·························@read.cnntp.org>,
 D Herring <········@at.tentpost.dot.com> wrote:

> Ron Garret wrote:
> > Consider the following code:
> > 
> > (eval-when (:load-toplevel :compile-toplevel :execute)
> > 
> >   (defconstant foo ...)
> > 
> >   (defun foo () foo)
> > 
> > )
> > 
> > Are there any circumstances under which, in an ANSI-compliant 
> > implementation of CL, (equal foo (foo)) can return NIL?
> ...
> > Discuss.
> 
> I like SBCL's take on this.
> http://www.sbcl.org/manual/Defining-Constants.html

Doesn't help (except in one very narrow case):


[···@mickey:~/Desktop]$ cat test.lisp

(eval-when (:compile-toplevel :load-toplevel :execute)

(defmacro define-constant (name value)
  `(defconstant ,name (if (boundp ',name) (symbol-value ',name) ,value)))

(define-constant c1 (get-internal-real-time))
(defun c1 () c1)

(define-constant c2 '#.(get-internal-real-time))
(defun c2 () c2)

(define-constant c3 (gensym))
(defun c3 () c3)

(define-constant c4 '#.(gensym))
(defun c4 () c4)

)
[···@mickey:~/Desktop]$ ccl -n
Welcome to Clozure Common Lisp Version 1.4-dev-r12255M-trunk  
(DarwinX8664)!
? (compile-file "test.lisp")
#P"/Users/ron/Desktop/test.dx64fsl"
NIL
NIL
? (list (eql c1 (c1)) (eql c2 (c2)) (eql c3 (c3)) (eql c4 (c4)))
(NIL T NIL T)
? (load "test.dx64fsl")
#P"/Users/ron/Desktop/test.dx64fsl"
? (list (eql c1 (c1)) (eql c2 (c2)) (eql c3 (c3)) (eql c4 (c4)))
(NIL T NIL NIL)
?
From: D Herring
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <4a403082$0$29137$6e1ede2f@read.cnntp.org>
Ron Garret wrote:
> In article <·························@read.cnntp.org>,
>  D Herring <········@at.tentpost.dot.com> wrote:
> 
>> Ron Garret wrote:
>>> Consider the following code:
>>>
>>> (eval-when (:load-toplevel :compile-toplevel :execute)
>>>
>>>   (defconstant foo ...)
>>>
>>>   (defun foo () foo)
>>>
>>> )
>>>
>>> Are there any circumstances under which, in an ANSI-compliant 
>>> implementation of CL, (equal foo (foo)) can return NIL?
>> ...
>>> Discuss.
>> I like SBCL's take on this.
>> http://www.sbcl.org/manual/Defining-Constants.html
> 
> Doesn't help (except in one very narrow case):
...
> [···@mickey:~/Desktop]$ cat test.lisp
...
> [···@mickey:~/Desktop]$ ccl -n
> ? (compile-file "test.lisp")
> ? (list (eql c1 (c1)) (eql c2 (c2)) (eql c3 (c3)) (eql c4 (c4)))
> (NIL T NIL T)
> ? (load "test.dx64fsl")
> ? (list (eql c1 (c1)) (eql c2 (c2)) (eql c3 (c3)) (eql c4 (c4)))
> (NIL T NIL NIL)

Interesting.  SBCL 1.0.24.47 gives
(T T T T)
(T T NIL NIL)

FWIW, :execute can be removed with the same results.

- Daniel
From: Kaz Kylheku
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <20090704042617.767@gmail.com>
On 2009-06-21, Ron Garret <·········@flownet.com> wrote:
> Consider the following code:
>
> (eval-when (:load-toplevel :compile-toplevel :execute)
>
>   (defconstant foo ...)
>
>   (defun foo () foo)
>
> )
>
> Are there any circumstances under which, in an ANSI-compliant 
> implementation of CL, (equal foo (foo)) can return NIL?
>
> It turns out that there are.  I'll describe what those circumstances are 
> in a moment (makes a good exercise to figure it out on your own).  The 
> question I want to raise is, given that this is the case, is this aspect 
> of DEFCONSTANT's behavior so at odds with intuition that it can be 
> considered broken?  And if so, what, if anything, should be done about 
> it?
>
> The circumstnaces under which (equal foo (foo)) can return NIL are the 
> following:
>
> 1.  FOO is initialized by a non-idempotent initialization function like 
> GENSYM or GET-INTERNAL-REAL-TIME.
>
> 2.  The code is compiled into a fasl file.
>
> The reason this can lead to (equal foo (foo)) being NIL is that the spec 
> says:
>
> "An implementation may choose to evaluate the value-form at compile 
> time, load time, OR BOTH." [Emphasis added.]

There is no way to fix this. Defconstants are not like Pascal constants
or C #define preprocessor symbols.

If you want that kind of constant in Lisp, there are things like read-time
evaluation, and define-symbol-macro.

If you compile a file containing defconstant which is used in that file,
fistly, the constant is used for compiling (which is like manifest constants
in some other languages), and secondly, the compiler must arrange for that
constant to become defined when the compiled file is loaded (which is
a dynamic language feature).

In Lisp, there is the notion of object similarity, and the concept is
involved in defining what kinds of objects must be externalizeable and
what that means.

Defconstant could be constrained such that the expression whcih gives a value
to the constant must be required to be an externalizeable object.  Then the
compilation semantics could be defined like this: the expression is evaluated
only at compile time. The externalizeable object is substituted wherever the
constant is referenced in the code being compiled. Moreover, the compiled file,
when loaded, constructs an object similar to that one, and defines that
constant with that object as its value.

However, this could be regarded as too limiting. Moreover, programmers could
still write defconstants whose value forms produce non-externalizeable objects
(like functions). The behavior of that would simply be undefined---a situation
no better than now.

It's better to have some freedom in defconstants. The way they work now,
you can given them values which are non-externalizeable, and make it all work.

> The "problem" (I put it in scare quotes because I consider it a problem 
> but reasonable people could disagree -- opening that discussion is the 
> point of posting this) is that "constant" can mean two different things:
>
> 1.  A value that the user is not allowed to change.
>
> 2.  A value that the compiler can assume (but is not obligated to 
> assume) won't change, but which might nonetheless actually change.
>
> The ANSI spec implicitly uses definition 2.  IMHO there is more utility 
> in definition 1.

But as you can see, there is also less utility in 1, because values that
change may still work as de-facto constants, and this may overcome the
externalizeability problem.

Suppose that I want a function as a constant:

  (defconstant +print-func+ #'princ)

How the heck can this work without evaluating the expression (function princ)
at compile time, and re-evaluating it again at load time?

You can't stick the function #'princ itself into the compiled file as an
externalized object!

Yet, by means of evaluating the initializing /expression/ at both compile
time and load time, ta da, we can actualy create a consistent constant that
works like a manifest constant at compile time, while denoting the same object
at run time also, even though that kind of object isn't externalizeable
in object files.

defconstant overcomes the externalizeability problem by externalizing the
source code of the expression, and allowing it to be evaluated in different
situations.

It's up to you to make these consistent, but you have the chance.

We just have the weak constraint that it must be possible to evaluate the
expression at compile time, and that in all contexts it evaluates to the same
value.

This is arguably better than some stricter bondage constraints, like for
instance requiring that the initializing expression must be constant
expression.
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-891A4A.18292422062009@news.albasani.net>
In article <··················@gmail.com>,
 Kaz Kylheku <········@gmail.com> wrote:

[A very lucid explanation of DEFCONSTANT]

> Suppose that I want a function as a constant:
> 
>   (defconstant +print-func+ #'princ)
> 
> How the heck can this work without evaluating the expression (function princ)
> at compile time, and re-evaluating it again at load time?

If compile-time and load-time are within a single Lisp session, I don't 
see why that should be a problem.  Why can't you recycle the 
compile-time value as the load-time value?

In fact, DEFVAR does exactly this.  Why couldn't DEFCONSTANT do exactly 
what DEFVAR does in terms of when it evaluates its initialization 
argument?

rg
From: Marcus Breiing
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <t5naws5wnr54x@breiing.com>
* Ron Garret

> If compile-time and load-time are within a single Lisp session, I
> don't see why that should be a problem. Why can't you recycle the
> compile-time value as the load-time value?
> In fact, DEFVAR does exactly this.

No, a variable defined by DEFVAR doesn't have a compile-time value.

You may get a better grip on the whole situation by thinking of
DEFCONSTANT as an "inline variable". Constantness is only imposed to
make inlining of its value by the compiler reasonably well-behaved.

Thinking about DEFCONSTANT as an "inline variable", you can also see
that the "single Lisp session" is a red herring. When your users
inline the current session's value when compiling files, then what
happens next session, when various compiled files are loaded?

Marcus
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-91277E.10082123062009@news.albasani.net>
In article <·············@breiing.com>,
 Marcus Breiing <······@2009w25.mail.breiing.com> wrote:

> * Ron Garret
> 
> > If compile-time and load-time are within a single Lisp session, I
> > don't see why that should be a problem. Why can't you recycle the
> > compile-time value as the load-time value?
> > In fact, DEFVAR does exactly this.
> 
> No, a variable defined by DEFVAR doesn't have a compile-time value.

It does if I wrap the DEFVAR in (eval-when (:compile-toplevel) ...

> You may get a better grip on the whole situation by thinking of
> DEFCONSTANT as an "inline variable". Constantness is only imposed to
> make inlining of its value by the compiler reasonably well-behaved.
>
> Thinking about DEFCONSTANT as an "inline variable", you can also see
> that the "single Lisp session" is a red herring. When your users
> inline the current session's value when compiling files, then what
> happens next session, when various compiled files are loaded?

That makes sense.  But then it seems to me that the concepts of "inline 
variable" and "immutable value" are being conflated, and imperfectly at 
that.  What I really want is an "immutable value" and it appears there's 
no way to achieve that in CL.  The best you can do is a lexical closure.  
Is that right?

rg
From: Raffael Cavallaro
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <h1r4em$all$1@news.eternal-september.org>
On 2009-06-23 13:08:21 -0400, Ron Garret <·········@flownet.com> said:

> What I really want is an "immutable value" and it appears there's
> no way to achieve that in CL.

Maybe I'm completely misunderstanding you, but aren't keyword symbols 
immutable in the sense that you need? e.g., :iterend can't be bound to 
some other value.
-- 
Raffael Cavallaro
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-C0800A.17042823062009@news.albasani.net>
In article <············@news.eternal-september.org>,
 Raffael Cavallaro <················@pas.espam.s.il.vous.plait.mac.com> 
 wrote:

> On 2009-06-23 13:08:21 -0400, Ron Garret <·········@flownet.com> said:
> 
> > What I really want is an "immutable value" and it appears there's
> > no way to achieve that in CL.
> 
> Maybe I'm completely misunderstanding you, but aren't keyword symbols 
> immutable in the sense that you need? e.g., :iterend can't be bound to 
> some other value.

Well, what I really wanted was a value that could not "accidentally" end 
up as a legitimate constituent of a sequence, for some value of 
"accidentally".  But I'm starting to think that whole idea was misguided 
to begin with.

rg
From: Kaz Kylheku
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <20090705175543.0@gmail.com>
On 2009-06-23, Ron Garret <·········@flownet.com> wrote:
> In article <·············@breiing.com>,
>  Marcus Breiing <······@2009w25.mail.breiing.com> wrote:
>
>> * Ron Garret
>> 
>> > If compile-time and load-time are within a single Lisp session, I
>> > don't see why that should be a problem. Why can't you recycle the
>> > compile-time value as the load-time value?
>> > In fact, DEFVAR does exactly this.
>> 
>> No, a variable defined by DEFVAR doesn't have a compile-time value.
>
> It does if I wrap the DEFVAR in (eval-when (:compile-toplevel) ...

It still doesn't have a compile-time value in the same sense that
a DEFCONSTANT does (and one which is not wrapped in eval-when!)

A constant has a compile-time value which pertains to the code being
compiled.

A compile-time defvar has a compile-time value which pertains to compile-time
code, like macro bodies and their helpers. Code being compiled is oblivious
to that compile-time defvar.

A compile-time definition is different from a compile-time inline value.
From: Vassil Nikolov
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <snziqimpfzy.fsf@luna.vassil.nikolov.name>
On Tue, 23 Jun 2009 10:08:21 -0700, Ron Garret <·········@flownet.com> said:
> ...
> What I really want is an "immutable value" and it appears there's
                           ^^^^^^^^^^^^^^^^^ [*]

  [*] I understand, of course, that we are talking about an immutable
      association between a name and a datum here, without implying or
      requiring anything about the immutability of the datum itself.

> no way to achieve that in CL.  The best you can do is a lexical closure.

  The user (not just the implementor), and without recourse to literal
  constants such as keyword symbols, can in fact achieve that if the
  (unnecessary) constraint that the name is a symbol is lifted; then
  it becomes fairly obvious how.

  ---Vassil.


-- 
Vassil Nikolov <········@pobox.com>

  (1) M(Gauss);
  (2) M(a) if M(b) and declared(b, M(a)),
  where M(x) := "x is a mathematician".
From: Kaz Kylheku
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <20090705161437.825@gmail.com>
On 2009-06-23, Ron Garret <·········@flownet.com> wrote:
> In article <··················@gmail.com>,
>  Kaz Kylheku <········@gmail.com> wrote:
>
> [A very lucid explanation of DEFCONSTANT]
>
>> Suppose that I want a function as a constant:
>> 
>>   (defconstant +print-func+ #'princ)
>> 
>> How the heck can this work without evaluating the expression (function princ)
>> at compile time, and re-evaluating it again at load time?
>
> If compile-time and load-time are within a single Lisp session, I don't 
> see why that should be a problem.

But in general they are not, and even if they are, defconstant does not
have a compile-time effect of defining the constant. (It only does
in the examples we have discussed, because those examples have
an eval-when set for compile-time-too via :compile-toplevel).

> Why can't you recycle the 
> compile-time value as the load-time value?

To recycle anything into load time, it has to be externalized in the compiled
file. This means it has to be an externalizeable kind of object, and some kind
of code is emitted which at load time will construct an object which is similar
to it, according to the similarity rules for that kind of externalizeable
object.

> In fact, DEFVAR does exactly this.
> Why couldn't DEFCONSTANT do exactly 
> what DEFVAR does in terms of when it evaluates its initialization 
> argument?

DEFVAR has no provision that the expression may be evaluated at compile time.
Dynamic variables are not folded at compile time, because their values
are allowed to change at run time.

If DEFCONSTANT were to be restricted to evaluating similarly to DEFVAR,
it would mean that there would be no compile-time evaluation, and thus the
optimization of constants would be prohibited.

DEFCONSTANT could be reformulated such that the evaluation is required to
happen only once. I.e. either at the load time of source code, or at compile
time of source, but the not at the load time of compiled code.

I think this is closer to what you want, but I wouldn't call it similar
to DEFVAR.
From: Duane Rettig
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <2df22bdb-0dab-40da-97aa-90b7b72c382c@g15g2000pra.googlegroups.com>
On Jun 23, 12:21 pm, Kaz Kylheku <········@gmail.com> wrote:
> On 2009-06-23, Ron Garret <·········@flownet.com> wrote:
>
> > In article <··················@gmail.com>,
> >  Kaz Kylheku <········@gmail.com> wrote:
>
> > [A very lucid explanation of DEFCONSTANT]
>
> >> Suppose that I want a function as a constant:
>
> >>   (defconstant +print-func+ #'princ)
>
> >> How the heck can this work without evaluating the expression (function princ)
> >> at compile time, and re-evaluating it again at load time?
>
> > If compile-time and load-time are within a single Lisp session, I don't
> > see why that should be a problem.
>
> But in general they are not, and even if they are, defconstant does not
> have a compile-time effect of defining the constant. (It only does
> in the examples we have discussed, because those examples have
> an eval-when set for compile-time-too via :compile-toplevel).
>
> > Why can't you recycle the
> > compile-time value as the load-time value?
>
> To recycle anything into load time, it has to be externalized in the compiled
> file. This means it has to be an externalizeable kind of object, and some kind
> of code is emitted which at load time will construct an object which is similar
> to it, according to the similarity rules for that kind of externalizeable
> object.

Remember also that the compiling lisp and the loading lisp might not
be the same lisp invocation.

> DEFCONSTANT could be reformulated such that the evaluation is required to
> happen only once. I.e. either at the load time of source code, or at compile
> time of source, but the not at the load time of compiled code.

How would you get that value into the loading lisp, if it were not the
compiling lisp?  E.g., how would you get this to work:

(defconstant myfunc #'foo)

without also having to change the language to redefine
externalizability for function objects and other currently non-
externalizable objects?

Duane
From: Thomas F. Burdick
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <083adcf2-909c-4527-9a6c-1942c50dde3d@i6g2000yqj.googlegroups.com>
On Jun 21, 10:39 pm, Ron Garret <·········@flownet.com> wrote:
> Consider the following code:
>
> (eval-when (:load-toplevel :compile-toplevel :execute)
>
>   (defconstant foo ...)
>
>   (defun foo () foo)
>
> )
 [snip]
> The "problem" (I put it in scare quotes because I consider it a problem
> but reasonable people could disagree -- opening that discussion is the
> point of posting this) is that "constant" can mean two different things:
>
> 1.  A value that the user is not allowed to change.
>
> 2.  A value that the compiler can assume (but is not obligated to
> assume) won't change, but which might nonetheless actually change.
>
> The ANSI spec implicitly uses definition 2.  IMHO there is more utility
> in definition 1.

Hi Ron,

I haven't read the whole thread (it got too flamey and I stopped), so
maybe you already addressed this. But it seems like you could use a
macro that expands into something like:

 (defconstant foo
   (if (boundp 'foo)
       (symbol-value 'foo)
       (gensym)))

And for what it's worth, I completely agree that the spec for
DEFCONSTANT is screwed up. The initialization semantics don't make
sense for constants, and it would be a lot more useful [*] if the spec
required that implementations raise an error if you bind or set a
constant. As it is, it's pretty much useless in portable code, unless
wrapped like the above, or to something like:

  (defconstant foo
    (cond
      ((not (boundp 'foo)) ... init form ...)
      ((equal (init-form) (symbol-value 'foo))
       (symbol-value 'foo))
      (t (error ...))))

Another work-around would be to stick your constants in a file that
you don't compile, and load only once.

[*] There are a lot of cases of things that would be useful but I
could see the implementors arguing that it would be significantly more
work, and maybe not worth the trade-off. Given that the spec already
requires that they get minimal compilation and some rather complex
scoping rules right, that's not the case here.
From: Ron Garret
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <rNOSPAMon-8C88FC.10114223062009@news.albasani.net>
In article 
<····································@i6g2000yqj.googlegroups.com>,
 "Thomas F. Burdick" <········@gmail.com> wrote:

> On Jun 21, 10:39�pm, Ron Garret <·········@flownet.com> wrote:
> > Consider the following code:
> >
> > (eval-when (:load-toplevel :compile-toplevel :execute)
> >
> > � (defconstant foo ...)
> >
> > � (defun foo () foo)
> >
> > )
>  [snip]
> > The "problem" (I put it in scare quotes because I consider it a problem
> > but reasonable people could disagree -- opening that discussion is the
> > point of posting this) is that "constant" can mean two different things:
> >
> > 1. �A value that the user is not allowed to change.
> >
> > 2. �A value that the compiler can assume (but is not obligated to
> > assume) won't change, but which might nonetheless actually change.
> >
> > The ANSI spec implicitly uses definition 2. �IMHO there is more utility
> > in definition 1.
> 
> Hi Ron,
> 
> I haven't read the whole thread (it got too flamey and I stopped), so
> maybe you already addressed this. But it seems like you could use a
> macro that expands into something like:
> 
>  (defconstant foo
>    (if (boundp 'foo)
>        (symbol-value 'foo)
>        (gensym)))

Yeah, we've been through that, and it doesn't work.

> And for what it's worth, I completely agree that the spec for
> DEFCONSTANT is screwed up.

Thank you for being the first person to actually answer the question 
that I asked!

> The initialization semantics don't make
> sense for constants, and it would be a lot more useful [*] if the spec
> required that implementations raise an error if you bind or set a
> constant. As it is, it's pretty much useless in portable code, unless
> wrapped like the above, or to something like:
> 
>   (defconstant foo
>     (cond
>       ((not (boundp 'foo)) ... init form ...)
>       ((equal (init-form) (symbol-value 'foo))
>        (symbol-value 'foo))
>       (t (error ...))))
> 
> Another work-around would be to stick your constants in a file that
> you don't compile, and load only once.

Hm, there's an interesting idea.  I honestly hadn't thought of that.  
Seems obvious in retrospect though.

> [*] There are a lot of cases of things that would be useful but I
> could see the implementors arguing that it would be significantly more
> work, and maybe not worth the trade-off. Given that the spec already
> requires that they get minimal compilation and some rather complex
> scoping rules right, that's not the case here.

Could be, but it seems unlikely.  Maybe changing DEFCONSTANT would be 
hard, but it's hard to believe that adding a new construct that defines 
an immutable value over a Lisp session would be that hard to write at 
the implementation level.

rg
From: Thomas F. Burdick
Subject: Re: Is DEFCONSTANT broken?
Date: 
Message-ID: <97402f45-de10-4350-ab96-5959b2d82c0f@h11g2000yqb.googlegroups.com>
On Jun 23, 7:11 pm, Ron Garret <·········@flownet.com> wrote:
> In article
> <····································@i6g2000yqj.googlegroups.com>,
>  "Thomas F. Burdick" <········@gmail.com> wrote:
>
> > Another work-around would be to stick your constants in a file that
> > you don't compile, and load only once.
>
> Hm, there's an interesting idea.  I honestly hadn't thought of that.  
> Seems obvious in retrospect though.

Simple ideas aren't always easy to think of :-). I saw a technique
like that in some old package of Lisp code that used custom build
scripts (Garnet maybe?) and have been using it since. The idea of
having files to load before building doesn't seem popular with the
authors of defsystem systems, but it seems to crop up in my real-life
build scripts (which usually invoke a defsystem as one step).

> > [*] There are a lot of cases of things that would be useful but I
> > could see the implementors arguing that it would be significantly more
> > work, and maybe not worth the trade-off. Given that the spec already
> > requires that they get minimal compilation and some rather complex
> > scoping rules right, that's not the case here.
>
> Could be, but it seems unlikely.  Maybe changing DEFCONSTANT would be
> hard, but it's hard to believe that adding a new construct that defines
> an immutable value over a Lisp session would be that hard to write at
> the implementation level.

I think we're agreeing here; and I think that was a particularly
poorly written paragraph on my part. Implementors already have to
tackle the mess of CL's scoping rules. They should be perfectly able
to implement non-settable non-bindable constants (and some do).