COMPGROUPS.NET | Search | Post Question | Groups | Stream | About | Register

### Is DEFCONSTANT broken?

• Email
• Follow

Consider the following code:

(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

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

 0
Reply rNOSPAMon (1926) 6/21/2009 8:39:37 PM

See related articles to this posting

Ron Garret <rNOSPAMon@flownet.com> writes:

> Consider the following code:
>
>
>   (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

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)-------------------------------
---------------------------------------------------------------

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
#:G10912
T
C/USER[10]>

--
__Pascal Bourguignon__

 0
Reply pjb (7873) 6/21/2009 9:50:45 PM

In article <87r5xd45oq.fsf@galatea.local>,
pjb@informatimago.com (Pascal J. Bourguignon) wrote:

> Ron Garret <rNOSPAMon@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
>
> 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,

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
> #:G10912
> 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:

[ron@mickey:~]$cat test.lisp (eval-when (:compile-toplevel :load-toplevel :execute) (defconstant foo (load-time-value (get-internal-real-time))) (defun foo () foo) ) [ron@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

 0
Reply rNOSPAMon (1926) 6/21/2009 10:41:49 PM

Ron Garret <rNOSPAMon@flownet.com> writes:

> In article <87r5xd45oq.fsf@galatea.local>,
>  pjb@informatimago.com (Pascal J. Bourguignon) wrote:
>
>> Ron Garret <rNOSPAMon@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

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

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,
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,
>
> 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
>> #:G10912
>> 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:
>
> [ron@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) > ) > [ron@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__

 0
Reply pjb (7873) 6/21/2009 11:53:47 PM

In article <87iqip3zzo.fsf@galatea.local>,
pjb@informatimago.com (Pascal J. Bourguignon) wrote:

> Ron Garret <rNOSPAMon@flownet.com> writes:
>
> > In article <87r5xd45oq.fsf@galatea.local>,
> >  pjb@informatimago.com (Pascal J. Bourguignon) wrote:
> >
> >> Ron Garret <rNOSPAMon@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
>
>
> 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)))
>

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

rg

 0
Reply rNOSPAMon (1926) 6/22/2009 1:12:02 AM

Ron Garret wrote:
> Consider the following code:
>
>
>   (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

Let's see them top that.

kt

 0
Reply kentilton (2985) 6/22/2009 3:30:33 AM

On Jun 21, 6:12=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote:
>
> Actually, DEFVAR comes closest to doing what I want. =A0But I also want t=
o
> insure that the value doesn't change or get bound.

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

-- Scott


 0
Reply FSet.SLB (346) 6/22/2009 4:46:48 AM

Ron Garret wrote:
> Consider the following code:
>
>
>   (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

 0
Reply dherring1 (564) 6/22/2009 5:35:20 AM

In article <4a3f1816$0$29136$6e1ede2f@read.cnntp.org>, D Herring <dherring@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): [ron@mickey:~/Desktop]$ cat test.lisp

(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)

)
[ron@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) ?   0 Reply rNOSPAMon (1926) 6/22/2009 6:15:51 AM In article <2e409792-6696-45b5-9474-636a45da86d2@j9g2000prh.googlegroups.com>, Scott Burson <FSet.SLB@gmail.com> wrote: > On Jun 21, 6:12�pm, Ron Garret <rNOSPA...@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: [ron@mickey:~/Desktop]$ cat test.lisp

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

)
[ron@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 ?   0 Reply rNOSPAMon (1926) 6/22/2009 6:26:23 AM On 2009-06-21, Ron Garret <rNOSPAMon@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.   0 Reply kkylheku (2499) 6/22/2009 7:01:51 AM On 2009-06-22, Ron Garret <rNOSPAMon@flownet.com> wrote: > In article ><2e409792-6696-45b5-9474-636a45da86d2@j9g2000prh.googlegroups.com>, > Scott Burson <FSet.SLB@gmail.com> wrote: > >> On Jun 21, 6:12 pm, Ron Garret <rNOSPA...@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: > > [ron@mickey:~/Desktop]$ cat test.lisp
>
>
> (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.

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

;; function only available in compiled form
(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.

 0
Reply kkylheku (2499) 6/22/2009 7:13:14 AM

On Jun 22, 3:12=A0am, Ron Garret <rNOSPA...@flownet.com> wrote:
> In article <87iqip3zzo....@galatea.local>,
> =A0p...@informatimago.com (Pascal J. Bourguignon) wrote:
>
>
>
>
>
> > Ron Garret <rNOSPA...@flownet.com> writes:
>
> > > In article <87r5xd45oq....@galatea.local>,
> > > =A0p...@informatimago.com (Pascal J. Bourguignon) wrote:
>
> > >> Ron Garret <rNOSPA...@flownet.com> writes:
>
> > >> > Consider the following code:
>
> > >> > (eval-when (:load-toplevel :compile-toplevel :execute)
>
> > >> > =A0 (defconstant foo ...)
>
> > >> > =A0 (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.
>
> > >> =A0 =A0 A constant defined by defconstant can be redefined with
> > >> =A0 =A0 defconstant. However, the consequences are undefined if an a=
ttempt
> > >> =A0 =A0 [...]
> > >> =A0 =A0 to assign it to a different value using a subsequent defcons=
tant.
>
> > > That's true. =A0But there are legitimate use-cases where this is quit=
e
> > > difficult for the user to achieve. =A0The particular use-case I'm thi=
nking
> > > 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. =A0The way I was taught =
to do
> > > that is with a gensym, but as you can see that can lead to difficulti=
es.
>
> > 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. =A0And
> > you would have to do some special things to do so. =A0For example:
>
> > =A0 =A0 (defconstant +x+ (gensym))
>
> > =A0 =A0 (defun f (x)
> > =A0 =A0 =A0 (case x
> > =A0 =A0 =A0 =A0 ((#.+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. =A0So restrictin=
g
> yourself to numbers doesn't help.
>
> > >> > It turns out that there are. =A0I'll describe what those circumsta=
nces are
> > >> > in a moment (makes a good exercise to figure it out on your own). =
=A0The
> > >> > 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? =A0And if so, what, if anything, should be done=
> > >> > it?
>
> > >> Yes, in a way we may consider defconstant to be broken. =A0What can =
be
> > >> done, is avoid using it.
>
> > > Would that be what you recommend?
>
> > Avoid using DEFCONSTANT. =A0Try DEFPARAMETER, it works better.
>
> Actually, DEFVAR comes closest to doing what I want. =A0But I also want t=
o
> 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

;; ## "The name of the lambda variable -ANSWER- is already in use to
name
;; a global variable."

 0
Reply larsnostdal (722) 6/22/2009 7:21:01 AM

On 2009-06-22, Kaz Kylheku <kkylheku@gmail.com> wrote:
> On 2009-06-22, Ron Garret <rNOSPAMon@flownet.com> wrote:
>> In article
>>  Scott Burson <FSet.SLB@gmail.com> wrote:
>>
>>> On Jun 21, 6:12 pm, Ron Garret <rNOSPA...@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:
>>
>> [ron@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.   0 Reply kkylheku (2499) 6/22/2009 7:56:59 AM In article <20090704042617.767@gmail.com>, Kaz Kylheku <kkylheku@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   0 Reply rNOSPAMon (1926) 6/23/2009 1:29:25 AM Ron Garret wrote: > In article <4a3f1816$0$29136$6e1ede2f@read.cnntp.org>,
>  D Herring <dherring@at.tentpost.dot.com> wrote:
>
>> Ron Garret wrote:
>>> Consider the following code:
>>>
>>>
>>>   (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):
....
> [ron@mickey:~/Desktop]$cat test.lisp .... > [ron@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)
> ? (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

 0
Reply dherring1 (564) 6/23/2009 1:31:46 AM

In article <20090704075344.622@gmail.com>,
Kaz Kylheku <kkylheku@gmail.com> wrote:

> On 2009-06-22, Ron Garret <rNOSPAMon@flownet.com> wrote:
> > In article
> >  Scott Burson <FSet.SLB@gmail.com> wrote:
> >
> >> On Jun 21, 6:12 pm, Ron Garret <rNOSPA...@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:
> >
> > [ron@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   0 Reply rNOSPAMon (1926) 6/23/2009 1:37:44 AM In article <20090704083602.686@gmail.com>, Kaz Kylheku <kkylheku@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   0 Reply rNOSPAMon (1926) 6/23/2009 1:46:16 AM * 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   0 Reply enometh (851) 6/23/2009 2:02:16 AM In article <m38wjjemhj.fsf@moon.robolove.meer.net>, Madhu <enometh@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   0 Reply rNOSPAMon (1926) 6/23/2009 2:20:33 AM * Ron Garret <rNOSPAMon-75AB80.19203322062009@news.albasani.net> : Wrote on Mon, 22 Jun 2009 19:20:33 -0700: | In article <m38wjjemhj.fsf@moon.robolove.meer.net>, | Madhu <enometh@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   0 Reply enometh (851) 6/23/2009 2:58:18 AM In article <m34ou7ejw5.fsf@moon.robolove.meer.net>, Madhu <enometh@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, barmar@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 ***   0 Reply barmar (6127) 6/23/2009 3:21:55 AM * Barry Margolin <barmar-665E86.23215522062009@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   0 Reply enometh (851) 6/23/2009 3:33:32 AM In article <m34ou7ejw5.fsf@moon.robolove.meer.net>, Madhu <enometh@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   0 Reply rNOSPAMon (1926) 6/23/2009 5:42:43 AM * Ron Garret <rNOSPAMon-6E490B.22424222062009@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   0 Reply enometh (851) 6/23/2009 6:24:05 AM Ron Garret <rNOSPAMon@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__   0 Reply pjb (7873) 6/23/2009 6:30:38 AM In article <87eitbzckx.fsf@galatea.local>, pjb@informatimago.com (Pascal J. Bourguignon) wrote: > Ron Garret <rNOSPAMon@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   0 Reply rNOSPAMon (1926) 6/23/2009 7:51:03 AM In article <m3vdmncvsq.fsf@moon.robolove.meer.net>, Madhu <enometh@meer.net> wrote: > * Ron Garret <rNOSPAMon-6E490B.22424222062009@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   0 Reply rNOSPAMon (1926) 6/23/2009 8:12:58 AM On Jun 23, 8:24=A0am, Madhu <enom...@meer.net> wrote: > The nasty connotation was meant to imply subversiveness; the opposite of > improving. Since when is subversiveness the opposite of improving?   0 Reply kodifik (223) 6/23/2009 8:22:30 AM Ron Garret <rNOSPAMon@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__   0 Reply pjb (7873) 6/23/2009 8:36:00 AM Ron Garret <rNOSPAMon@flownet.com> writes: > In article <87eitbzckx.fsf@galatea.local>, > pjb@informatimago.com (Pascal J. Bourguignon) wrote: > >> Ron Garret <rNOSPAMon@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__   0 Reply pjb (7873) 6/23/2009 8:47:21 AM On Jun 23, 3:37=A0am, Ron Garret <rNOSPA...@flownet.com> wrote: > In article <20090704075344....@gmail.com>, > =A0Kaz Kylheku <kkylh...@gmail.com> wrote: > > > > > > > On 2009-06-22, Ron Garret <rNOSPA...@flownet.com> wrote: > > > In article > > ><2e409792-6696-45b5-9474-636a45da8...@j9g2000prh.googlegroups.com>, > > > =A0Scott Burson <FSet....@gmail.com> wrote: > > > >> On Jun 21, 6:12=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote: > > > >> > Actually, DEFVAR comes closest to doing what I want. =A0But 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: > > > > [ron@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
>
> > It's evaluated again, just like the initializing value of defconstant.
>
>
> > =A0 ;; macro only at compile time
> > =A0 (eval-when (:compile-toplevel)
> > =A0 =A0(define-symbol-macro c7 '#.(gensym)))
>
> > =A0 ;; function only available in compiled form
> > =A0 =A0(defun c7 () c7))
>
> > Now the problem goes away: there is /no/ C7 symbol macro when you load
> > the object file. =A0And 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. =A0My actual use case is that I want to define a
> guardian value to use as an indication of an exceptional situation. =A0
> Specifically, I want to use it in code that implements something like
> Python iterators to indicate end-of-iteration. =A0I also want users to be
> able to define their own iterators. =A0So the actual code looks something
> like this:
>
> (defconstant +iterend+ (gensym-or-something-similar))
>
> (defmacro iterloop (iterator)
> =A0 ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>
> (defmethod iterator ((thing class)) ... (when ... (return +iterend+)))
>
> or something like that. =A0(If you want to see the actual code it's inhtt=
p://www.flownet.com/ron/lisp/rg-utils.lisp). =A0But 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..

"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?

 0
Reply larsnostdal (722) 6/23/2009 9:02:59 AM

On Jun 21, 10:39=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote:
> Consider the following code:
>
>
> =A0 (defconstant foo ...)
>
> =A0 (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. =A0A value that the user is not allowed to change.
>
> 2. =A0A 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. =A0IMHO 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.

 0
Reply tburdick (337) 6/23/2009 10:34:50 AM

* 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


 0

pjb@informatimago.com (Pascal J. Bourguignon) writes:

> Ron Garret <rNOSPAMon@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...

 0
Reply see95 (257) 6/23/2009 11:43:09 AM

Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) writes:

> pjb@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Ron Garret <rNOSPAMon@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...

--
__Pascal Bourguignon__

 0
Reply pjb (7873) 6/23/2009 12:03:39 PM

pjb@informatimago.com (Pascal J. Bourguignon) writes:

> Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) writes:
>
>> pjb@informatimago.com (Pascal J. Bourguignon) writes:
>>
>>> Ron Garret <rNOSPAMon@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...
>

I'd use THROW for what Ron wants to do, though.

 0
Reply see95 (257) 6/23/2009 1:51:46 PM

Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) writes:

> pjb@informatimago.com (Pascal J. Bourguignon) writes:
>
>> Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) writes:
>>
>>> pjb@informatimago.com (Pascal J. Bourguignon) writes:
>>>
>>>> Ron Garret <rNOSPAMon@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...
>>
>
> 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__

 0
Reply pjb (7873) 6/23/2009 1:58:52 PM

Ron Garret <rNOSPAMon@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

 0
Reply barry_fishman1 (68) 6/23/2009 3:37:58 PM

In article <m3my7z2c6h.fsf@barry_fishman.acm.org>,
Barry Fishman <barry_fishman@acm.org> wrote:

> Ron Garret <rNOSPAMon@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

rg

 0
Reply rNOSPAMon (1926) 6/23/2009 5:01:40 PM

In article <t5naws5wnr54x@breiing.com>,
Marcus Breiing <usenet@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

 0
Reply rNOSPAMon (1926) 6/23/2009 5:08:21 PM

In article
"Thomas F. Burdick" <tburdick@gmail.com> wrote:

> On Jun 21, 10:39�pm, Ron Garret <rNOSPA...@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

> 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

 0
Reply rNOSPAMon (1926) 6/23/2009 5:11:42 PM

In article
Lars Rune N�stdal <larsnostdal@gmail.com> wrote:

> On Jun 23, 3:37�am, Ron Garret <rNOSPA...@flownet.com> wrote:
> > In article <20090704075344....@gmail.com>,
> > �Kaz Kylheku <kkylh...@gmail.com> wrote:
> >
> >
> >
> >
> >
> > > On 2009-06-22, Ron Garret <rNOSPA...@flownet.com> wrote:
> > > > In article
> > > > �Scott Burson <FSet....@gmail.com> wrote:
> >
> > > >> On Jun 21, 6:12�pm, Ron Garret <rNOSPA...@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:
> >
> > > > [ron@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   0 Reply rNOSPAMon (1926) 6/23/2009 5:14:33 PM In article <7czlbzpcsv.fsf@pbourguignon.anevia.com>, pjb@informatimago.com (Pascal J. Bourguignon) wrote: > Ron Garret <rNOSPAMon@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   0 Reply rNOSPAMon (1926) 6/23/2009 5:16:13 PM Ron Garret <rNOSPAMon@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   0 Reply russell_mcmanus (151) 6/23/2009 5:17:37 PM In article <m2d48vfa5u.fsf@wyoming.home>, Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) wrote: > pjb@informatimago.com (Pascal J. Bourguignon) writes: > > > Ron Garret <rNOSPAMon@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   0 Reply rNOSPAMon (1926) 6/23/2009 5:18:15 PM In article <m263enf47h.fsf@wyoming.home>, Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) wrote: > pjb@informatimago.com (Pascal J. Bourguignon) writes: > > > Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) writes: > > > >> pjb@informatimago.com (Pascal J. Bourguignon) writes: > >> > >>> Ron Garret <rNOSPAMon@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   0 Reply rNOSPAMon (1926) 6/23/2009 5:18:51 PM In article <7cy6rjpc9y.fsf@pbourguignon.anevia.com>, pjb@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   0 Reply rNOSPAMon (1926) 6/23/2009 5:25:47 PM On Jun 23, 1:42=A0am, Ron Garret <rNOSPA...@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. =A0However, that I hav= e > this agenda is hardly a secret. =A0I 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?   0 Reply larryliberty (26) 6/23/2009 5:34:03 PM On 2009-06-23 13:08:21 -0400, Ron Garret <rNOSPAMon@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   0 Reply raffaelcavallaro5985 (306) 6/23/2009 5:45:14 PM On Jun 23, 7:14=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote: > In article > <9af29dff-e5a1-4b13-9359-459ef1c90...@i6g2000yqj.googlegroups.com>, > =A0Lars Rune N=F8stdal <larsnost...@gmail.com> wrote: > > > > > > > On Jun 23, 3:37=A0am, Ron Garret <rNOSPA...@flownet.com> wrote: > > > In article <20090704075344....@gmail.com>, > > > =A0Kaz Kylheku <kkylh...@gmail.com> wrote: > > > > > On 2009-06-22, Ron Garret <rNOSPA...@flownet.com> wrote: > > > > > In article > > > > ><2e409792-6696-45b5-9474-636a45da8...@j9g2000prh.googlegroups.com>= , > > > > > =A0Scott Burson <FSet....@gmail.com> wrote: > > > > > >> On Jun 21, 6:12=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote: > > > > > >> > Actually, DEFVAR comes closest to doing what I want. =A0But 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: > > > > > > [ron@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
>
> > > > It's evaluated again, just like the initializing value of defconsta=
nt.
>
>
> > > > =A0 ;; macro only at compile time
> > > > =A0 (eval-when (:compile-toplevel)
> > > > =A0 =A0(define-symbol-macro c7 '#.(gensym)))
>
> > > > =A0 ;; function only available in compiled form
> > > > =A0 (eval-when (:load-toplevel)
> > > > =A0 =A0(defun c7 () c7))
>
> > > > Now the problem goes away: there is /no/ C7 symbol macro when you l=
> > > > the object file. =A0And if you load the source file, there is no c7
> > > > function.
>
> > > > Just like in C, there are no more #define constants when you're loa=
ding
> > > > .o
> > > > files. And you can't run source without compiling it. (That's not r=
eal
> > > > programming; you're supposed to edit, compile, then run, right?)
>
> > > > So, everything is cool.
>
> > > That won't work for me. =A0My actual use case is that I want to defin=
e a
> > > guardian value to use as an indication of an exceptional situation. =
=A0
> > > Specifically, I want to use it in code that implements something like
> > > Python iterators to indicate end-of-iteration. =A0I also want users t=
o be
> > > able to define their own iterators. =A0So the actual code looks somet=
hing
> > > like this:
>
> > > (defconstant +iterend+ (gensym-or-something-similar))
>
> > > (defmacro iterloop (iterator)
> > > =A0 ... (if (eq (funcall iterator) +iterend+) (return)) ...)
>
> > > (defmethod iterator ((thing class)) ... (when ... (return +iterend+))=
)
>
> > > or something like that. =A0(If you want to see the actual code it's
> > > inhttp://www.flownet.com/ron/lisp/rg-utils.lisp). =A0But 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..
>
> > =A0 ..can't be bound: *check*
> > =A0 ..can't be set: =A0 *check*
>
> > ..or..
>
> > =A0 (let (('answer 42))
> > =A0 =A0 "No way.")
>
> > =A0 (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. =A0However, 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. =A0So 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. =A0So it has to be an uninterned symbol=
.. =A0
> 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. =A0And then you want to make sure
> that that binding never changes.
>
> rg


 0
Reply larsnostdal (722) 6/23/2009 5:52:00 PM

On 2009-06-23, Ron Garret <rNOSPAMon@flownet.com> wrote:
> In article <20090704042617.767@gmail.com>,
>  Kaz Kylheku <kkylheku@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.

 0
Reply kkylheku (2499) 6/23/2009 7:21:42 PM

On 2009-06-23, Ron Garret <rNOSPAMon@flownet.com> wrote:
> In article <t5naws5wnr54x@breiing.com>,
>  Marcus Breiing <usenet@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.

 0
Reply kkylheku (2499) 6/23/2009 7:30:51 PM

On Jun 23, 7:14=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote:
> In article
> =A0Lars Rune N=F8stdal <larsnost...@gmail.com> wrote:
>
>
>
>
>
> > On Jun 23, 3:37=A0am, Ron Garret <rNOSPA...@flownet.com> wrote:
> > > In article <20090704075344....@gmail.com>,
> > > =A0Kaz Kylheku <kkylh...@gmail.com> wrote:
>
> > > > On 2009-06-22, Ron Garret <rNOSPA...@flownet.com> wrote:
> > > > > In article
,
> > > > > =A0Scott Burson <FSet....@gmail.com> wrote:
>
> > > > >> On Jun 21, 6:12=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote:
>
> > > > >> > Actually, DEFVAR comes closest to doing what I want. =A0But 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:
>
> > > > > [ron@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 defconsta= nt. > > > > > How about this: > > > > > =A0 ;; macro only at compile time > > > > =A0 (eval-when (:compile-toplevel) > > > > =A0 =A0(define-symbol-macro c7 '#.(gensym))) > > > > > =A0 ;; function only available in compiled form > > > > =A0 (eval-when (:load-toplevel) > > > > =A0 =A0(defun c7 () c7)) > > > > > Now the problem goes away: there is /no/ C7 symbol macro when you l= oad > > > > the object file. =A0And if you load the source file, there is no c7 > > > > function. > > > > > Just like in C, there are no more #define constants when you're loa= ding > > > > .o > > > > files. And you can't run source without compiling it. (That's not r= eal > > > > programming; you're supposed to edit, compile, then run, right?) > > > > > So, everything is cool. > > > > That won't work for me. =A0My actual use case is that I want to defin= e a > > > guardian value to use as an indication of an exceptional situation. = =A0 > > > Specifically, I want to use it in code that implements something like > > > Python iterators to indicate end-of-iteration. =A0I also want users t= o be > > > able to define their own iterators. =A0So the actual code looks somet= hing > > > like this: > > > > (defconstant +iterend+ (gensym-or-something-similar)) > > > > (defmacro iterloop (iterator) > > > =A0 ... (if (eq (funcall iterator) +iterend+) (return)) ...) > > > > (defmethod iterator ((thing class)) ... (when ... (return +iterend+))= ) > > > > or something like that. =A0(If you want to see the actual code it's > > > inhttp://www.flownet.com/ron/lisp/rg-utils.lisp). =A0But 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.. > > > =A0 ..can't be bound: *check* > > =A0 ..can't be set: =A0 *check* > > > ..or.. > > > =A0 (let (('answer 42)) > > =A0 =A0 "No way.") > > > =A0 (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. =A0However, 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. =A0So 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. =A0So it has to be an uninterned symbol= .. =A0 > But then to use it you have to bind it to something precisely because > you can't generate it any other way. =A0And 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.   0 Reply tburdick (337) 6/23/2009 7:36:42 PM On Jun 23, 7:11=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote: > In article > <083adcf2-909c-4527-9a6c-1942c50dd...@i6g2000yqj.googlegroups.com>, > =A0"Thomas F. Burdick" <tburd...@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. =A0I honestly hadn't thought of that. = =A0 > 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. =A0Maybe 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).   0 Reply tburdick (337) 6/23/2009 7:46:34 PM On 2009-06-23, Ron Garret <rNOSPAMon@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.   0 Reply kkylheku (2499) 6/23/2009 7:52:51 PM On Jun 22, 6:46=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote: > In article <20090704083602....@gmail.com>, > =A0Kaz Kylheku <kkylh...@gmail.com> wrote: > > > =A0 (eval-when (:load-toplevel) > > =A0 =A0 (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. =A0However, it's not really > what I want. =A0The main reason I want to use DEFCONSTANT is to prevent c= 7 > from being reassigned or rebound. =A0If C7 is a symbol macro I don't get > that guarantee. =A0If 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   0 Reply FSet.SLB (346) 6/23/2009 9:40:50 PM On Jun 22, 6:37=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote: > > That won't work for me. =A0My actual use case is that I want to define a > guardian value to use as an indication of an exceptional situation. =A0 > Specifically, I want to use it in code that implements something like > Python iterators to indicate end-of-iteration. =A0I also want users to be > able to define their own iterators. =A0So the actual code looks something > like this: > > (defconstant +iterend+ (gensym-or-something-similar)) > > (defmacro iterloop (iterator) > =A0 ... (if (eq (funcall iterator) +iterend+) (return)) ...) > > (defmethod iterator ((thing class)) ... (when ... (return +iterend+))) > > or something like that. =A0(If you want to see the actual code it's inhtt= p://www.flownet.com/ron/lisp/rg-utils.lisp). =A0But 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   0 Reply FSet.SLB (346) 6/23/2009 9:43:54 PM On Jun 23, 10:25=A0am, Ron Garret <rNOSPA...@flownet.com> wrote: > In article <7cy6rjpc9y....@pbourguignon.anevia.com>, > =A0p...@informatimago.com (Pascal J. Bourguignon) wrote: > > > I doubt you really need to use the value at compilation time. > > I'm sure I don't. =A0The only thing I really need is immutability. =A0And= 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. =A0But see below... > > > > I would also > > > like to prevent the user from shooting themselves in the foot by bind= ing > > > or assigning the value. > > > Then use a symbol macro. =A0Notice that defconstant doesn't prevent the > > user to assign a value to the constant _variable_. =A0Only CL says it > > has undefined consequences. =A0The user is always free to shoot himself > > in the feet. > > Wow, you're right. =A0I could have sworn it was an error (every > implementation I've tried makes it an error) but you're right, it's not. = =A0 > 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   0 Reply duane8 (1153) 6/23/2009 9:58:40 PM On Jun 23, 12:21=A0pm, Kaz Kylheku <kkylh...@gmail.com> wrote: > On 2009-06-23, Ron Garret <rNOSPA...@flownet.com> wrote: > > > In article <20090704042617....@gmail.com>, > > =A0Kaz Kylheku <kkylh...@gmail.com> wrote: > > > [A very lucid explanation of DEFCONSTANT] > > >> Suppose that I want a function as a constant: > > >> =A0 (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 comp= iled > 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 s= imilar > 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 comp= ile > 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   0 Reply duane8 (1153) 6/23/2009 10:07:51 PM On 2009-06-23, Ron Garret <rNOSPAMon@flownet.com> wrote: > In article <20090704083602.686@gmail.com>, > Kaz Kylheku <kkylheku@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.   0 Reply kkylheku (2499) 6/23/2009 10:18:37 PM On Jun 23, 2:40=A0pm, Scott Burson <FSet....@gmail.com> wrote: > On Jun 22, 6:46=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote: > > > In article <20090704083602....@gmail.com>, > > =A0Kaz Kylheku <kkylh...@gmail.com> wrote: > > > > =A0 (eval-when (:load-toplevel) > > > =A0 =A0 (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. =A0However, it's not real= ly > > what I want. =A0The main reason I want to use DEFCONSTANT is to prevent= c7 > > from being reassigned or rebound. =A0If C7 is a symbol macro I don't ge= t > > that guarantee. =A0If 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   0 Reply duane8 (1153) 6/23/2009 10:20:34 PM On 2009-06-23, Paul Foley <see@below.invalid> wrote: > pjb@informatimago.com (Pascal J. Bourguignon) writes: > >> Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) writes: >> >>> pjb@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.   0 Reply kkylheku (2499) 6/23/2009 10:36:03 PM In article <20090705204915.242@gmail.com>, Kaz Kylheku <kkylheku@gmail.com> wrote: > On 2009-06-23, Ron Garret <rNOSPAMon@flownet.com> wrote: > > In article <20090704083602.686@gmail.com>, > > Kaz Kylheku <kkylheku@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   0 Reply rNOSPAMon (1926) 6/23/2009 11:40:08 PM In article <02d09e17-2bb7-401c-82c0-6199f7336a65@g15g2000pra.googlegroups.com>, Scott Burson <FSet.SLB@gmail.com> wrote: > On Jun 22, 6:37�pm, Ron Garret <rNOSPA...@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   0 Reply rNOSPAMon (1926) 6/23/2009 11:42:33 PM In article <35913e98-c73c-4b7c-9212-22b33166b2af@12g2000pri.googlegroups.com>, Duane Rettig <duane@franz.com> wrote: > On Jun 23, 10:25�am, Ron Garret <rNOSPA...@flownet.com> wrote: > > In article <7cy6rjpc9y....@pbourguignon.anevia.com>, > > �p...@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   0 Reply rNOSPAMon (1926) 6/23/2009 11:57:46 PM In article <87hby6lvim.fsf@thelonious.cl-user.org>, Russell McManus <russell_mcmanus@yahoo.com> wrote: > Ron Garret <rNOSPAMon@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   0 Reply rNOSPAMon (1926) 6/23/2009 11:58:47 PM In article <20090705182649.997@gmail.com>, Kaz Kylheku <kkylheku@gmail.com> wrote: > On 2009-06-23, Ron Garret <rNOSPAMon@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   0 Reply rNOSPAMon (1926) 6/23/2009 11:59:50 PM In article <b75fdb8a-6682-4954-b91e-8a087b81069c@k38g2000yqh.googlegroups.com>, "Thomas F. Burdick" <tburdick@gmail.com> wrote: > On Jun 23, 7:14�pm, Ron Garret <rNOSPA...@flownet.com> wrote: > > In article > > <9af29dff-e5a1-4b13-9359-459ef1c90...@i6g2000yqj.googlegroups.com>, > > �Lars Rune N�stdal <larsnost...@gmail.com> wrote: > > > > > > > > > > > > > On Jun 23, 3:37�am, Ron Garret <rNOSPA...@flownet.com> wrote: > > > > In article <20090704075344....@gmail.com>, > > > > �Kaz Kylheku <kkylh...@gmail.com> wrote: > > > > > > > On 2009-06-22, Ron Garret <rNOSPA...@flownet.com> wrote: > > > > > > In article > > > > > ><2e409792-6696-45b5-9474-636a45da8...@j9g2000prh.googlegroups.com>, > > > > > > �Scott Burson <FSet....@gmail.com> wrote: > > > > > > > >> On Jun 21, 6:12�pm, Ron Garret <rNOSPA...@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: > > > > > > > > [ron@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
> >
> > > > > It's evaluated again, just like the initializing value of
> > > > > defconstant.
> >
> >
> > > > > � ;; 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
> > > > > .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

rg

 0
Reply rNOSPAMon (1926) 6/24/2009 12:01:08 AM

In article <h1r4em$all$1@news.eternal-september.org>,
Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com>
wrote:

> On 2009-06-23 13:08:21 -0400, Ron Garret <rNOSPAMon@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

 0
Reply rNOSPAMon (1926) 6/24/2009 12:04:28 AM

On Jun 23, 3:20 pm, Duane Rettig <du...@franz.com> wrote:
> On Jun 23, 2:40 pm, Scott Burson <FSet....@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

 0
Reply FSet.SLB (346) 6/24/2009 12:09:24 AM

Ron Garret <rNOSPAMon@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

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__

 0
Reply pjb (7873) 6/24/2009 12:15:07 AM

Kaz Kylheku <kkylheku@gmail.com> writes:

> On 2009-06-23, Paul Foley <see@below.invalid> wrote:
>> pjb@informatimago.com (Pascal J. Bourguignon) writes:
>>
>>> Paul Foley <see@below.invalid> (http://public.xdi.org/=pf) writes:
>>>
>>>> pjb@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...
>>>
>>
>> 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))))))

 0
Reply see95 (257) 6/24/2009 12:48:01 AM

On Jun 23, 4:57=A0pm, Ron Garret <rNOSPA...@flownet.com> wrote:
> In article
> =A0Duane Rettig <du...@franz.com> wrote:
>
>
>
>
>
> > On Jun 23, 10:25=A0am, Ron Garret <rNOSPA...@flownet.com> wrote:
> > > In article <7cy6rjpc9y....@pbourguignon.anevia.com>,
> > > =A0p...@informatimago.com (Pascal J. Bourguignon) wrote:
>
> > > > I doubt you really need to use the value at compilation time.
>
> > > I'm sure I don't. =A0The only thing I really need is immutability. =
=A0And I
> > > thought the only way I coyld get immutability in CL is with DEFCONSTA=
NT,
> > > and that at least potentially gives me a compile time value whether I
> > > like it or not. =A0But 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. =A0Notice that defconstant doesn't prevent=
the
> > > > user to assign a value to the constant _variable_. =A0Only CL says =
it
> > > > has undefined consequences. =A0The user is always free to shoot him=
self
> > > > in the feet.
>
> > > Wow, you're right. =A0I could have sworn it was an error (every
> > > implementation I've tried makes it an error) but you're right, it's n=
ot. =A0
> > > 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. =A0If 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. =A0I thought DEFCONSTANT was unique in that it
> provided an immutability guarantee. =A0In 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. =A0I was so convinced o=
f
> 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? =A0What 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

 0
Reply duane8 (1153) 6/24/2009 12:56:45 AM

On Jun 23, 5:09=A0pm, Scott Burson <FSet....@gmail.com> wrote:
> On Jun 23, 3:20 pm, Duane Rettig <du...@franz.com> wrote:
>
> > On Jun 23, 2:40 pm, Scott Burson <FSet....@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

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

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

> =A0For 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. =A0I 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]." =A0I 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
and I'd prefer not to rehash it; perhaps someone can point to the

> 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)
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

 0
Reply duane8 (1153) 6/24/2009 1:17:19 AM

On Tue, 23 Jun 2009 10:08:21 -0700, Ron Garret <rNOSPAMon@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 <vnikolov@pobox.com>

(1) M(Gauss);
(2) M(a) if M(b) and declared(b, M(a)),
where M(x) := "x is a mathematician".

 0
Reply vnikolov1 (276) 6/24/2009 1:39:13 AM

On Jun 23, 6:17=A0pm, Duane Rettig <du...@franz.com> wrote:
> On Jun 23, 5:09=A0pm, Scott Burson <FSet....@gmail.com> wrote:
>
> > On Jun 23, 3:20 pm, Duane Rettig <du...@franz.com> wrote:
>
> > > On Jun 23, 2:40 pm, Scott Burson <FSet....@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. =A0But then your program would be write-only. =A0What 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
>
> As do we all; that's why warnings are given by most implementations
> when a constant is redefined.

Right.

> > =A0For 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. =A0I 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. =A0In 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. =A0 (load-time-value *empty- > entry-marker*)) > ) > > (defvar *empty-entry-marker* =A0 (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   0 Reply FSet.SLB (346) 6/24/2009 4:23:45 AM On Jun 23, 9:23=A0pm, Scott Burson <FSet....@gmail.com> wrote: > On Jun 23, 6:17=A0pm, Duane Rettig <du...@franz.com> wrote: > > > > > > > On Jun 23, 5:09=A0pm, Scott Burson <FSet....@gmail.com> wrote: > > > > On Jun 23, 3:20 pm, Duane Rettig <du...@franz.com> wrote: > > > > > On Jun 23, 2:40 pm, Scott Burson <FSet....@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 sor= t > > > > 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. i= t > > > should be more like DEFVAR). > > > Perhaps. =A0But then your program would be write-only. =A0What do you d= o > > when you realize that you made a mistake? > > Perhaps MAKUNBOUND would do for this. =A0It'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? > > > =A0For 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 coul= d > > > 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. =A0I don't know if the spec should have mandated such helpfulne= ss, > > > 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. =A0In 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. =A0 (load-time-value *empty-
> > entry-marker*))
> > )
>
> > (defvar *empty-entry-marker* =A0 (list :empty))
>
> > Then in our code we reference .empty-entry-marker.
>
> So you don't try to use DEFCONSTANT for this either. =A0Sounds 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

 0
Reply duane8 (1153) 6/24/2009 5:32:45 AM

In article
Duane Rettig <duane@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

 0
Reply rNOSPAMon (1926) 6/24/2009 7:17:02 AM

In article
Duane Rettig <duane@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   0 Reply rNOSPAMon (1926) 6/24/2009 7:21:44 AM On Jun 24, 12:17=A0am, Ron Garret <rNOSPA...@flownet.com> wrote: > In article > <c395d253-3a33-439f-8630-418d589d0...@o5g2000prh.googlegroups.com>, > =A0Duane Rettig <du...@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 providin= g > > > an immutability guarantee, what is it for? =A0What can you do with > > > DEFCONSTANT in portable CL that you can't do with a symbol macro? > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0^^^^^^^^^^= ^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > > > > 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   0 Reply duane8 (1153) 6/24/2009 7:23:24 AM In article <d2f1d093-371f-448d-889f-bf73608ba3e8@a5g2000pre.googlegroups.com>, Duane Rettig <duane@franz.com> wrote: > On Jun 24, 12:17�am, Ron Garret <rNOSPA...@flownet.com> wrote: > > In article > > <c395d253-3a33-439f-8630-418d589d0...@o5g2000prh.googlegroups.com>, > > �Duane Rettig <du...@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   0 Reply rNOSPAMon (1926) 6/24/2009 8:24:31 AM On Jun 23, 10:32=A0pm, Duane Rettig <du...@franz.com> wrote: > On Jun 23, 9:23=A0pm, Scott Burson <FSet....@gmail.com> wrote: > > > On Jun 23, 6:17=A0pm, Duane Rettig <du...@franz.com> wrote: > > > > On Jun 23, 5:09=A0pm, Scott Burson <FSet....@gmail.com> wrote: > > > > > On Jun 23, 3:20 pm, Duane Rettig <du...@franz.com> wrote: > > > > > > On Jun 23, 2:40 pm, Scott Burson <FSet....@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 s= ort > > > > > 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 b= e > > > > better if it didn't assign a new value on repeated evaluation (i.e.= it > > > > should be more like DEFVAR). > > > > Perhaps. =A0But then your program would be write-only. =A0What do you= do > > > when you realize that you made a mistake? > > > Perhaps MAKUNBOUND would do for this. =A0It'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. > > > > =A0For 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 co= uld > > > > e.g. warn you, when loading a fasl file, if the current value of th= e > > > > declared constant differs from the one the function was compiled > > > > with. =A0I don't know if the spec should have mandated such helpful= ness, > > > > but I think DEFCONSTANT would be more useful if at least the high-e= nd > > > > 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 yo= u > > > 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

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

 0
Reply FSet.SLB (346) 6/25/2009 2:51:11 AM

On Jun 24, 7:51=A0pm, Scott Burson <FSet....@gmail.com> wrote:
> On Jun 23, 10:32=A0pm, Duane Rettig <du...@franz.com> wrote:
>
>
>
>
>
> > On Jun 23, 9:23=A0pm, Scott Burson <FSet....@gmail.com> wrote:
>
> > > On Jun 23, 6:17=A0pm, Duane Rettig <du...@franz.com> wrote:
>
> > > > On Jun 23, 5:09=A0pm, Scott Burson <FSet....@gmail.com> wrote:
>
> > > > > On Jun 23, 3:20 pm, Duane Rettig <du...@franz.com> wrote:
>
> > > > > > On Jun 23, 2:40 pm, Scott Burson <FSet....@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. =A0But then your program would be write-only. =A0What do y=
ou do
> > > > when you realize that you made a mistake?
>
> > > Perhaps MAKUNBOUND would do for this. =A0It'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. =A0I 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.

> > > > > =A0For 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. =A0I don't know if the spec should have mandated such helpf=
ulness,
> > > > > 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. > > ??? =A0I proposed that for each compiled function the implementation > would remember all values of constants integrated into the compiled > code. =A0Even constant-heavy code is going to have what, on average -- > two or three of these per routine? =A0How 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   0 Reply duane8 (1153) 6/25/2009 7:27:45 AM Duane Rettig <duane@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__   0 Reply pjb (7873) 6/25/2009 8:28:02 AM On Jun 25, 1:28=A0am, p...@informatimago.com (Pascal J. Bourguignon) wrote: > Duane Rettig <du...@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. =A0 > > 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. =A0For 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). =A0Then 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), =A0than 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   0 Reply duane8 (1153) 6/25/2009 5:17:18 PM Duane Rettig <duane@franz.com> writes: > On Jun 25, 1:28�am, p...@informatimago.com (Pascal J. Bourguignon) > wrote: >> Duane Rettig <du...@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__   0 Reply pjb (7873) 6/25/2009 8:27:13 PM On Jun 25, 1:27=A0pm, p...@informatimago.com (Pascal J. Bourguignon) wrote: > Duane Rettig <du...@franz.com> writes: > > On Jun 25, 1:28=A0am, p...@informatimago.com (Pascal J. Bourguignon) > > wrote: > >> Duane Rettig <du...@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. = =A0 > > >> 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. =A0There'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. =A0For a start, assemble= r > >> is harder to read than high level language. > > > Harder for whom or what? =A0 It's certainly easier to read for the > > executing machine. =A0And we're not talking about readability, but > > complexity. =A0And, 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. =A0You 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. =A0But I'm aware of > the difference, only I don't think it's signficative. =A0My 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... > > =A0=A0Then 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. =A0A 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. =A0 No, the simplest code is the fully-unrolled loop which > > executes no branches, but which simply performs the required > > instructions. =A0Is 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. =A0Which is mostly inventing new > levels of source code generating the existing lower level of lisp, VOP > or binary. =A0If 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   0 Reply duane8 (1153) 6/25/2009 9:31:07 PM pjb@informatimago.com (Pascal J. Bourguignon) writes: > Duane Rettig <duane@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.   0 Reply paul-donnelly (264) 6/25/2009 9:48:48 PM Duane Rettig <duane@franz.com> writes: > On Jun 25, 1:27�pm, p...@informatimago.com (Pascal J. Bourguignon) > wrote: >> Duane Rettig <du...@franz.com> writes: >> > On Jun 25, 1:28�am, p...@informatimago.com (Pascal J. Bourguignon) >> > wrote: >> >> Duane Rettig <du...@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__   0 Reply pjb (7873) 6/25/2009 11:04:39 PM Paul Donnelly <paul-donnelly@sbcglobal.net> writes: > pjb@informatimago.com (Pascal J. Bourguignon) writes: > >> Duane Rettig <duane@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 > =E2=80=9Ccomplexity=E2=80=9D. Duane's definition in this context seems to= be that > complex code is that which requires more legwork =E2=80=94 a more involved > series of steps =E2=80=94 for the computer to execute. Obviously interpre= ting > 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. --=20 __Pascal Bourguignon__   0 Reply pjb (7873) 6/25/2009 11:06:39 PM In article <347951c7-8b5c-43fb-b6f1-111ef52dfb7e@w31g2000prd.googlegroups.com>, Duane Rettig <duane@franz.com> wrote: > On Jun 25, 1:28�am, p...@informatimago.com (Pascal J. Bourguignon) > wrote: > > Duane Rettig <du...@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   0 Reply rNOSPAMon (1926) 6/26/2009 1:34:47 AM Ron Garret <rNOSPAMon@flownet.com> writes: > In article > <347951c7-8b5c-43fb-b6f1-111ef52dfb7e@w31g2000prd.googlegroups.com>, > Duane Rettig <duane@franz.com> wrote: > >> On Jun 25, 1:28�am, p...@informatimago.com (Pascal J. Bourguignon) >> wrote: >> > Duane Rettig <du...@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__   0 Reply pjb (7873) 6/26/2009 2:10:50 AM In article <7cy6rgn2el.fsf_-_@pbourguignon.anevia.com>, pjb@informatimago.com (Pascal J. Bourguignon) wrote: > Duane Rettig <duane@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, barmar@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 *** `  0 Reply barmar (6127) 6/26/2009 2:14:59 AM 93 Replies 54 Views Similar Articles 12/6/2013 9:35:54 PM [PageSpeed]  Reply: Similar Artilces: Broken Pipe Hi all, when I use unix command "cat", sometime, it will display the error message "Brokon pipe". Would anyone help to solve it? Many thanks. Ming 2004-10-26, 07:49(-07), Ming: > Hi all, when I use unix command "cat", sometime, it will display the > error message "Brokon pipe". Would anyone help to solve it? [...] This happens when cat is writting to a pipe, and there's noone reading at the other end of the pipe, and the SIGPIPE signal is ignored:$ (trap '' PIPE; cat /kernel/genunix) | : cat: write error: Broken pipe It is not normal that cat ignores the SIGPIPE. On normal conditions, cat should exit gracefully upon reception of the signal. $(cat /kernel/genunix; echo$? >&2) | : 141 (cat generated no error message and exited with status 141, which means it was killed by a SIGPIPE signal (128 + 13 (SIGPIPE = 13 here on Solaris)). -- Stephane

aip.sty broken?
When using the minimal example below, which uses the aip.sty to format references, I get an error for the \cite command: <snip> ! Missing \endcsname inserted. <to be read again> \mathsurround l.6 ...ions which exhibit nonidealities \cite{A06} with ? <snip> Interestingly, if I replace the \cite{A06} command with \citea{\citenum{A06}} (mentioned in aip.sty as being equal to \cite), the document gets processed and displays the expected result (superscript reference, correct formatting in the list of references

Fork broken???
groups.google.com, don't use the broken "Reply" link at the bottom of the article. Click on "show options" at the top of the article, then click on the "Reply" at the bottom of the article headers. ishulz wrote: > This is simple prog: > > #!/usr/bin/perl -w > system('/usr/local/bin/cat aaa'); > > It works fine and $? = 0 > > But this prog: > > #!/usr/bin/perl -w > system('/usr/bin/ls aaa >bbb'); > > doesn't work, and$?=65280, $!='No such file or directory' > > '/usr/bin/ls aaa >bbb Fedora: distributing broken code http://www.linuxsecurity.com/content/view/122480/102/ "Two broken language packs were inadvertently included in the previous Firefox update. This caused issues such as an error dialog appearing upon startup of the browser, or certain plugins and extensions not working." On Mon, 24 Apr 2006 20:40:04 -0400, DFS wrote: > http://www.linuxsecurity.com/content/view/122480/102/ > > "Two broken language packs were inadvertently included in the > previous Firefox update. This caused issues such as an > error dialog appearing upon startup of the browser, or > certain plugins and extensions not working." Big deal. Got anything better to do with your life than this? ... thought not. Idiot. You seem to think only Linux has bugs. Wiser people know this to be utterly untrue. -- Kier On Tue, 25 Apr 2006 09:42:57 +0100, Kier wrote: > On Mon, 24 Apr 2006 20:40:04 -0400, DFS wrote: > >> http://www.linuxsecurity.com/content/view/122480/102/ >> >> "Two broken language packs were inadvertently included in the >> previous Firefox update. This caused issues such as an >> error dialog appearing upon startup editing sketch patterns broken? would someone like to confirm that linear and circular patterns cannot be edited by dragging the arrowed points in 2003 sp4 please,-wasn't this what 3.1 was about?? Movie15 broken with Powerdot Hello all! I have a presentation with the Powerdot class and it loads in a movie with the movie15 package. When I wrote the presentation last March, it worked perfectly, but now, after a miktex update, the movie no longer gets included in the presentation. This is with the latest versions of miktex and the packages on WinXP. I've reduced it to a minimal case: \documentclass{powerdot} \usepackage{movie15} \begin{document} \begin{slide}{test} \includemovie{5cm}{5cm}{applegrowth.avi} \end{slide} \end{document} It seems that contents of the last argument in the includemovie command are ZLIB1.DLL 1.2.5 is broken This is repeat message, I have posted this before I tried using the recently released ZLIB1.DLL version 1.2.5 with Visual Studio 2008 (C++) Microsoft LINK complained of multiple '.text' sections found with different attributes and after that, unzipping (programmatically that is) causes memory protection faults and the program terminates. So I am reverting back to the previous ZLIB1.DLL version 1.2.3 I am surprised that few have noticed this (one other peron on scouring the Internet). <update> From 5th message here http://www.masm32.com/board/index.php?PHPSESSID=0c22bf4d3124 URL context constructor broken? the code, and studied the JavaDoc. Since there are no examples, the matter of what SHOULD it do, still seems ambiguous. For now, The best approach is to write a replacement that is quite forgiving. Sometimes the goofs even forget the lead / on the newlocation string. It makes no sense unless you presume one. Browsers seem to sort this out. Then I need to write a SSCCE that demonstrates each of the non-functioning patterns in simplest form. I will leave it up to Oracle to decide if they intended it to be broken for the purpose I am trying to use it. It is the sort of bug broken file icons I have a couple of favorite Classic applications that I want to use in Tiger's Classic environment. In each case, when I copy the application file to the disk in my Mac Mini, it shows up with the icon of a torn paper. Apparently my Mac Mini sees them as pieces of split files. Do I need to change something in the file attributes? In article <e0oplk$b1c4\$1@news3.infoave.net>, Sawney Beane <XXbeadle@qwickconnect.net> wrote: > I have a couple of favorite Classic applications that I want to use in > Tiger's Classic environment. In each case, when I copy the appl

Write to PNG broken?
Hello, while creating a VI to report some information I wanted to use the "Write PNG File.vi". With Labview 8.2.1 under Windows XP everything works fine. With the same Labview version under Linux "Write PNG File.vi" and the similar jpeg vi's are broken and can't be executed. As they are password protected I can't look inside for the cause of the error. Does anybody has similar issues with these image vi's under linux or maybe even has a hint how to fix/circumvent this? Alexander