In article <3130831277715...@naggum.no>, Erik Naggum <e...@naggum.no> wrote:
> * Vassil Nikolov <vniko...@poboxes.com> > | Let me offer you this point of view. There are three kinds of special > | variables: > | > | (1) Global special variables... > | (2) Local special variables... > | (3) Implicit special variables...
> PROGV doesn't seem to fit either of these categories. should it?
No, indeed it does not and it should not.
You are right in pointing out that I was not quite precise. I should have written something like, `three kinds of special variables that exist/are specified at program-writing time (compile time).' (This is probably not the best formulation.)
Then there is, of course, as you write, the issue of variables being created at run time. I mean those created with INTERN, GENSYM, etc., whose values are got/set with SYMBOL-VALUE and SETF thereof, and which are bound with PROGV.
Now things start getting complicated here. If the list of variable names given to PROGV is a constant, are the variables not actually specified at program-writing time? Or, consider a macro expansion function that calls GENSYM to produce local variables: what is run time for the macro expansion function is compile time for the function containing the macro call. Or, there may be mixes (whether desired or not), e.g. when one obtains a string at run time, interns it, and passes it to SYMBOL-VALUE or PROGV, and the symbol thus produced happens to be one that appears in a special declaration.
I don't have any ready answers here; it's not that I have no thoughts on this matter, but if I have to formulate them, I shall need to take time thinking them over. In my previous posting, I offered just a simplification which I believed had some practical value in spite of not being comprehensive.
I also see now that I am less certain about a terminological issue than I would like to be. I must have identified special and dynamic variables (well, in fact so does the CLHS glossary, but that is not an excuse...). I am not saying that there should be a semantic distinction, but from a pragmatic point of view `special' could be taken to imply that the variable is declared or at least `declarable'---i.e. that it exists at compile time. On the other hand, I cannot declare anything about variables created at run time (well, again we come to the issue that one program's run time may be another program's compile time).
Well, if one accepts this distinction between `special' and `dynamic' (I know this might be a big `if'), then PROGV is not about special variables in this sense of `special,' and the statement in my previous posting should be taken in this sense. But this would have excused me if I had thought about this issue in advance.
I shall be happy to read comments on these matters.
Vassil Nikolov <vniko...@poboxes.com> www.poboxes.com/vnikolov (You may want to cc your posting to me if I _have_ to see it.) LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
In article <djsob1c7ij....@planet.praeclarus.demon.co.uk>, aaron.cr...@pobox.com (Aaron Crane) wrote:
> In article <7csm6k$31...@nnrp1.dejanews.com>, > Vassil Nikolov <vniko...@poboxes.com> writes: (...) > > (2) Would this be the same as writing a DYNAMIC-LET for Common Lisp in > > terms of SETF of SYMBOL-FUNCTION and UNWIND-PROTECT? (Again shallow > > binding only.)
> Yes, I think so (modulo the shallow-binding thing, and assuming that you > meant SYMBOL-VALUE rather than SYMBOL-FUNCTION).
(...)
Yes, SYMBOL-VALUE of course. My mistake (was thinking at the same time, is Linear B a functional language...).
Vassil Nikolov <vniko...@poboxes.com> www.poboxes.com/vnikolov (You may want to cc your posting to me if I _have_ to see it.) LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
In article <bICI2.13$kM2.772@burlma1-snr2>, Barry Margolin <bar...@bbnplanet.com> wrote: (...)
> Are deep bindings every really used in serious implementations? I've > rarely encountered it, and I tend to think of them more as an issue for > academic discussion of design techniques. The benefit of deep binding is > that stack unwinding is cheap, but at the expense of slow dynamic variable > access, and this seems like a poor tradeoff.
I think Lucid Common Lisp 3.0 (Sun Common Lisp 3.0) had them (don't know about newer versions), and it was a pretty serious implementation. Also, didn't Zeta Lisp with its stack groups implement deep binding?
To me, the benefit of deep binding is that in a multithreading Lisp every thread's dynamic bindings are its own. But let more knowledgeable people speak on this issue.
Of course, it is well known that you can't have all three operations--- (1) bind a dynamic variable; (2) lookup/set a dynamic variable; (3) change the dynamic environment (context switch)---in O(1). I believe support of multithreading is an important factor as to which tradeoff is to be preferred.
Vassil Nikolov <vniko...@poboxes.com> www.poboxes.com/vnikolov (You may want to cc your posting to me if I _have_ to see it.) LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
> Anyway, to return to Vassil's earlier question: (...) > Suppose that you're using a Lisp where you cannot SETQ or LET special > variables, and where (DYNAMIC name) and (SETF (DYNAMIC name)) do the right > thing, but where DYNAMIC-LET doesn't exist. One possible implementation > would be as follows.
> This doesn't seem to correspond exactly to either shallow or deep binding: > there's no explicit stack of old values, and there's no global alist of > dynamic bindings. But consing a vector of the old values at runtime and > then allowing the vector to be GCed when control leaves the DYNAMIC-LET is > equivalent to manipulating a stack of values; since that is the case, this > is presumably a slightly obscure case of shallow binding.
Yes, I think so too, that this is essentially shallow binding.
Once again, my `litmus test' for shallow/deep binding is whether it would affect other threads.
> I think your question is probably best answered by saying that if you want > to use deep binding for specials, it has to be built in to the > implementation at a low level -- and this is precisely because for deep > binding, dynamic variable access is more complex than simply looking at the > value cell of the relevant symbol.
Indeed.
In fact, this realisation cooled my excitement about writing a LETF macro, which would be something like LET for SETF places---but would `bind' them only in a shallow way, and have doubtful universal usefulness. (Would be implemented similarly to the above macro.)
Vassil Nikolov <vniko...@poboxes.com> www.poboxes.com/vnikolov (You may want to cc your posting to me if I _have_ to see it.) LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
* Barry Margolin <bar...@bbnplanet.com> | Are deep bindings every really used in serious implementations? I've | rarely encountered it, and I tend to think of them more as an issue for | academic discussion of design techniques. The benefit of deep binding is | that stack unwinding is cheap, but at the expense of slow dynamic | variable access, and this seems like a poor tradeoff.
there may be a reason to use deep binding in a multiprocessing environment where you may have to switch contexts very often and this should be virtually free. switching values of a whole bunch of bindings in a context switch can get expensive in shallow binding. I don't know if this would actually hold true in any real system or in any real use, but it's worth noting that context switching is expensive, and perhaps we will find the best solutions in unexpected corners of the solution space.
Erik Naggum <e...@naggum.no> writes: > there may be a reason to use deep binding in a multiprocessing > environment where you may have to switch contexts very often and this > should be virtually free. switching values of a whole bunch of bindings > in a context switch can get expensive in shallow binding. I don't know > if this would actually hold true in any real system or in any real use, > but it's worth noting that context switching is expensive, and perhaps we > will find the best solutions in unexpected corners of the solution space.
And in a multiprocessing environment that runs on multiple CPUS, where there is no `context switch' this is even worse.
Vassil Nikolov <vniko...@poboxes.com> writes: > In article <djoglodf42....@planet.praeclarus.demon.co.uk>, > aaron.cr...@pobox.com (Aaron Crane) wrote: > > (defmacro dynamic-let (bindings &body body) <snip> > > I think your question is probably best answered by saying that if you want > > to use deep binding for specials, it has to be built in to the > > implementation at a low level -- and this is precisely because for deep > > binding, dynamic variable access is more complex than simply looking at the > > value cell of the relevant symbol.
> Indeed. In fact, this realisation cooled my excitement about writing a > LETF macro,
The pseudo-CL support in Emacs Lisp does actually provide this macro.
C-h f letf RET:
: `letf' is a compiled Lisp macro : -- loaded from "cl-macs.elc" : (letf BINDINGS &rest BODY) : : (letf ((PLACE VALUE) ...) BODY...): temporarily bind to PLACEs. : This is the analogue of `let', but with generalized variables (in the : sense of `setf') for the PLACEs. Each PLACE is set to the corresponding : VALUE, then the BODY forms are executed. On exit, either normally or : because of a `throw' or error, the PLACEs are set back to their original : values. Note that this macro is *not* available in Common Lisp. : As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)', : the PLACE is not modified before executing BODY.
> which would be something like LET for SETF places---but would `bind' them > only in a shallow way, and have doubtful universal usefulness.
I'm not sure how `universally useful' it is. A grep over the Lisp source of XEmacs 20.4 found only two occurrences. But that said, as long as the caller understands that it's just a macro for UNWIND-PROTECTing a temporary replacement value for a place, it seems fairly useful to me.
> (Would be implemented similarly to the above macro.)
By the way, it occurs to me that the macro I suggested needs some work to be generally useful. As it stands, it doesn't correctly introduce new dynamic bindings -- it should check whether the binding exists beforehand, and if not, it should MAKUNBOUND the binding afterwards.
-- Aaron Crane <aaron.cr...@pobox.com> <URL:http://pobox.com/~aaronc/> ** Please send on-topic followups by Usenet, not email **
In article <36F31455.35F0C...@IntelliMarket.Com>, Kelly Murray <k...@IntelliMarket.Com> wrote: (...)
> The real loser in this deal is truly global variables, > since you must always waste time scanning the binding stack, > instead of just going directly to the value cell. > In my true-multiprocessor TopCL implementation, > I added (defglobal var val) that told the compiler to > generate straight value-cell lookups to avoid the problem.
> But CL variables like *print-pretty* and friends, which > are not often bound but in some cases looked-up often, > e.g. #'format e.g. it can slow things down.
> This is why special variables are to be avoided, > and even eliminated if possible...unless > you really need a dynamically bound variable.
Indeed.
If I need a `bindable' global variable, I just have to grin and bear it.
If I need an unbindable and unchangeable global variable, this is in fact no variable but a constant, and I have DEFCONSTANT, with O(1) access time (not to mention possibilities for optimisation).
Now, the point---what if I need an unbindable but changeable global variable in Common Lisp (i.e. I don't have DEFGLOBAL) which is accessible (both for reading and writing) in O(1)?
I can't do (DEFCONSTANT FOO (MAKE-ARRAY NIL)) and then (AREF FOO) for getting the value and (SETF (AREF FOO) value) ;ERROR! for setting the value, though perhaps it would have been nice if I could. Using the function value of a symbol (which is changeable but unbindable) directly is not allowed for arbitrary objects so the best way I know is to use a closure: use
and make things look like a real variable by using DEFINE-SYMBOL-MACRO, defining SETF of GET-FOO, and declaiming GET-FOO and SET-FOO inline.
Is there any better way?
Vassil Nikolov <vniko...@poboxes.com> www.poboxes.com/vnikolov (You may want to cc your posting to me if I _have_ to see it.) LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
Vassil Nikolov <vniko...@poboxes.com> writes: > I can't do (DEFCONSTANT FOO (MAKE-ARRAY NIL)) and then > (AREF FOO) for getting the value and (SETF (AREF FOO) value) ;ERROR! > for setting the value, though perhaps it would have been nice if > I could.
But allocating a single-element array will work just fine, or, perhaps better, a structure with one slot. Then you just need suitable GLOBAL and (SETF GLOBAL) syntax, and you're home and dry.
Vassil Nikolov wrote: > .. . > I can't do (DEFCONSTANT FOO (MAKE-ARRAY NIL)) and then > (AREF FOO) for getting the value and (SETF (AREF FOO) value) ;ERROR! > for setting the value, though perhaps it would have been nice if > I could. ...
Why not? I don't beleive that the object which is the value of a defconstant is to be considered immutable, only the binding itself.
If you want to do (setf (aref foo index) value), you can't do: (defconstant foo '#(1 2 3)) or (defconstant foo (load-time-value (make-array 3 :initial-contents '(1 2 3) t)) ....or similarly for (defvar foo ...), but that's because of the immutability of the value, not the binding.
> Vassil Nikolov wrote: > > .. . > > I can't do (DEFCONSTANT FOO (MAKE-ARRAY NIL)) and then > > (AREF FOO) for getting the value and (SETF (AREF FOO) value) ;ERROR! > > for setting the value, though perhaps it would have been nice if > > I could. ...
> Why not? > I don't beleive that the object which is the value of a defconstant is > to be considered immutable, only the binding itself.
I think it's immutable. I don't have a cite offhand, but I'll hunt around. I think you have to say DEFPARAMETER if you don't want the compiler to treat it like a literal constant.
> If you want to do (setf (aref foo index) value), you can't do: > (defconstant foo '#(1 2 3)) > or > (defconstant foo (load-time-value (make-array 3 :initial-contents '(1 2 > 3) t)) > ....or similarly for (defvar foo ...), but that's because of the > immutability of the value, not the binding.
I don't think this makes any sense. defconstant exists to allow compile-time resolution. saying to make the thing at load-time is more like nesting eval-when of :load-toplevel inside an eval-when of :compile-toplevel. The nesting isn't intuitive.
> > I can't do (DEFCONSTANT FOO (MAKE-ARRAY NIL)) and then > > (AREF FOO) for getting the value and (SETF (AREF FOO) value) ;ERROR! > > for setting the value, though perhaps it would have been nice if > > I could.
> But allocating a single-element array will work just fine, or, perhaps > better, a structure with one slot. Then you just need suitable GLOBAL > and (SETF GLOBAL) syntax, and you're home and dry.
Sorry, I don't get your point. A zero-dimensional array is my favourite single-slot structure; but I need to refer to it somehow--- if not by a global variable or a global function (which is a lexical closure), how else? (I mean, without amending Common Lisp to have global lexicals (I believe this is the name for what I have wanted in this thread).)
Vassil Nikolov <vniko...@poboxes.com> www.poboxes.com/vnikolov (You may want to cc your posting to me if I _have_ to see it.) LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
> > Vassil Nikolov wrote: > > > .. . > > > I can't do (DEFCONSTANT FOO (MAKE-ARRAY NIL)) and then > > > (AREF FOO) for getting the value and (SETF (AREF FOO) value) ;ERROR! > > > for setting the value, though perhaps it would have been nice if > > > I could. ...
> > Why not? > > I don't beleive that the object which is the value of a defconstant is > > to be considered immutable, only the binding itself.
> I think it's immutable. I don't have a cite offhand, but I'll hunt > around.
This time I have the exact reference. I also used to think that just the binding was immutable (and maybe it was that way in CLtL, 1st ed.), but then I read that:
3.2.2.3 Semantic Constraints (...) 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.
(Well, as Humpty Dumpty said, `There's glory for us!')
So (defconstant bad-foo (make-array nil) "single-slot") (setf (aref bad-foo) 'bar) is in error.
> I think you have to say DEFPARAMETER if you don't want the compiler to > treat it like a literal constant.
Yes, but DEFPARAMETER is no different from DEFVAR with respect to being fast or slow in lookup of the variable's value, so DEFPARAMETER was of no interest to me for the purpose of this particular (self-imposed) exercise.
Vassil Nikolov <vniko...@poboxes.com> www.poboxes.com/vnikolov (You may want to cc your posting to me if I _have_ to see it.) LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
> In article <sfwbthlqshb....@world.std.com>, > Kent M Pitman <pit...@world.std.com> wrote: >> "Howard R. Stearns" <how...@elwood.com> writes:
>> > Vassil Nikolov wrote: >> > > .. . >> > > I can't do (DEFCONSTANT FOO (MAKE-ARRAY NIL)) and then >> > > (AREF FOO) for getting the value and (SETF (AREF FOO) value) ;ERROR! >> > > for setting the value, though perhaps it would have been nice if >> > > I could. ...
>> > Why not? >> > I don't beleive that the object which is the value of a defconstant is >> > to be considered immutable, only the binding itself.
>> I think it's immutable. I don't have a cite offhand, but I'll hunt >> around.
> This time I have the exact reference. I also used to think that just > the binding was immutable (and maybe it was that way in CLtL, 1st ed.), > but then I read that:
> 3.2.2.3 Semantic Constraints > (...) > 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.
It says the object, not the contents of the object. To me, this means that the variable binding is immutable, not the object itsself. Whether someplace else it says the object's contents are also immutable I don't know. I would hope not. I thought the purpose of defconstant was so the compiler could infer the type and size of the object and make optimizations based upon that.
mike...@mikemac.com (Mike McDonald) writes: > It says the object, not the contents of the object. To me, this means that > the variable binding is immutable, not the object itsself. Whether someplace > else it says the object's contents are also immutable I don't know. I would > hope not. I thought the purpose of defconstant was so the compiler could infer > the type and size of the object and make optimizations based upon that.
The problem is a little different than that, actually. I believe you are perfectly in line if you want to modify the contents of the object. But in one program that is what I was relying on, and wrote code like this:
In one file:
(defconstant +eof+ (list nil))
In another:
(read foo-stream nil nil +eof+)
(I believe that is the right syntax for reading from a stream and having it return an object rather than signal an error on EOF. In any case, that's irrelevant to the point.)
Worked as expected in lispworks, but MCL barfed. Apparently, a possible interpretation of the standard is that the values of contants do not have to remain eq to each other across different source files. I forget the exact reasoning, but that is what it came down to. Digitool advised me to change over to defvar to get around this problem.
In other words, an implementation conforms to the standard if it re-evaluates and reconstructs a constant's value in each source file. The idea for the fast global variable, in other words, is not guaranteed to work in all implementations.
* ANSI X3.226-1994 | 3.2.2.3 Semantic Constraints | (...) | 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.
* mike...@mikemac.com (Mike McDonald) | It says the object, not the contents of the object.
I think you need to look up `literal object':
literal adj. (of an object) referenced directly in a program rather than being computed by the program; that is, appearing as data in a quote form, or, if the object is a self-evaluating object, appearing as unquoted data. ``In the form (cons "one" '("two")), the expressions "one", ("two"), and "two" are literal objects.''
such objects are immutable:
constant object n. an object that is constrained (e.g., by its context in a program or by the source from which it was obtained) to be immutable. ``A literal object that has been processed by compile-file is a constant object.''
mike...@mikemac.com (Mike McDonald) writes: > It says the object, not the contents of the object. To me, this > means that the variable binding is immutable, not the object > itsself. Whether someplace else it says the object's contents are > also immutable I don't know. I would hope not.
I don't think it makes any sense for a literal object to contain non-literals; it wouldn't be literal! Therefore when the spec says it's a literal object then it has to be literal all the way down.
> The problem is a little different than that, actually. I believe you are > perfectly in line if you want to modify the contents of the object. But in > one program that is what I was relying on, and wrote code like this:
> In one file:
> (defconstant +eof+ (list nil))
> In another:
> (read foo-stream nil nil +eof+)
> (I believe that is the right syntax for reading from a stream and having it > return an object rather than signal an error on EOF. In any case, that's > irrelevant to the point.)
> Worked as expected in lispworks, but MCL barfed. Apparently, a possible > interpretation of the standard is that the values of contants do not have > to remain eq to each other across different source files. I forget the > exact reasoning, but that is what it came down to. Digitool advised me to > change over to defvar to get around this problem.
> In other words, an implementation conforms to the standard if it > re-evaluates and reconstructs a constant's value in each source file. The > idea for the fast global variable, in other words, is not guaranteed to > work in all implementations.
I don't know whether this was true at some point, but the following text in the ANSI spec contradicts your interpretation.
"The side effects of the execution of defconstant must be equivalent to at least the side effects of the execution of the following code:
> OK, let me try and recall a somewhat distorted (since I was a newbie when I > was exposed to this argument) version of the argument.
> Consider (defconstant *foo* '(())). There are two ways to look at this > constant. The constant exists independent of the source code is one. The > alternative is that the constant is subject to the compile time > environment. As I understand it, the compile time environment does not have > to be the same as the run time environment, which is where forms such as > eval-when come in and play a role. While compiling therefore an > implementation is allowed to reconstruct the value of a constant, rather > than obtain it from some globally correct value. In other words, while > compiling the implementation is allowed to substitute in the value of a > constant and then produce a fasl, rather than look up the value in the > current run-time environment when the compiled code is loaded.
> Effectively, this produces a situation where the constant does not preserve > its value across source files. So while the defconstant behaves as the spec > dictates, the result of compiling code containing the constant is counter- > intuitive.
> Again, this is coming down through mists of time and ignorance, so a better > informed comment would be very useful.
Ahh, I see. I understand the argument, and it seems intuitive, but I'd like to get the CLHS to agree. Here's what I came up with:
Later in the description of defconstant, CLHS says:
"An implementation may choose to evaluate the value-form at compile time, load time, or both. Therefore, users must ensure that the initial-value can be evaluated at compile time (regardless of whether or not references to name appear in the file) and that it always evaluates to the same value."
The CLHS glossary defines "same" as follows (eliding irrelevant sub-definitions):
"same adj. [...] 2. (of objects if no predicate is implied by context) indistinguishable by eql. Note that eq might be capable of distinguishing some numbers and characters which eql cannot distinguish, but the nature of such, if any, is implementation-dependent. Since eq is used only rarely in this specification, eql is the default predicate when none is mentioned explicitly. ``The conses returned by two successive calls to cons are never the same.'' [...]"
The first sentence seems applicable, since no context (i.e. no statement of the form "... the same under <predicate>") is given in the definition of defconstant.
Backing up a bit, I notice the phrase "users must ensure ... and that it always evaluates to the same value."
Combining this with the final sentence (two conses never the same) of the "same" glossary entry quoted above, I think I see how your example's behavior is allowed: If I create a program containing the form (defconstant *foo* '(())) then I have failed to ensure that the initial value is the same at compile time and load time. If the implementation evaluates the defconstant form at both compile and load time, it will cons two different initial values.
So, now for the $2^16 question: Have I interpreted this correctly?
> * ANSI X3.226-1994 >| 3.2.2.3 Semantic Constraints >| (...) >| 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.
> * mike...@mikemac.com (Mike McDonald) >| It says the object, not the contents of the object.
> I think you need to look up `literal object':
> literal adj. (of an object) referenced directly in a program rather than > being computed by the program; that is, appearing as data in a quote form, > or, if the object is a self-evaluating object, appearing as unquoted data. > ``In the form (cons "one" '("two")), the expressions "one", ("two"), and > "two" are literal objects.''
> such objects are immutable:
> constant object n. an object that is constrained (e.g., by its context in a > program or by the source from which it was obtained) to be immutable. ``A > literal object that has been processed by compile-file is a constant object.''
> #:Erik
So the (hyper) spec uses "constant object" for immutable things. defconstant doesn't signify that the object is constant, only that using the binding of the symbol has to be equivilent to using the literal form.
OK, let me try and recall a somewhat distorted (since I was a newbie when I was exposed to this argument) version of the argument.
Consider (defconstant *foo* '(())). There are two ways to look at this constant. The constant exists independent of the source code is one. The alternative is that the constant is subject to the compile time environment. As I understand it, the compile time environment does not have to be the same as the run time environment, which is where forms such as eval-when come in and play a role. While compiling therefore an implementation is allowed to reconstruct the value of a constant, rather than obtain it from some globally correct value. In other words, while compiling the implementation is allowed to substitute in the value of a constant and then produce a fasl, rather than look up the value in the current run-time environment when the compiled code is loaded.
Effectively, this produces a situation where the constant does not preserve its value across source files. So while the defconstant behaves as the spec dictates, the result of compiling code containing the constant is counter- intuitive.
Again, this is coming down through mists of time and ignorance, so a better informed comment would be very useful.
Vassil Nikolov <vniko...@poboxes.com> writes: > Yes, but DEFPARAMETER is no different from DEFVAR with respect to being > fast or slow in lookup of the variable's value, so DEFPARAMETER was of > no interest to me for the purpose of this particular (self-imposed) > exercise.
> I think it's immutable. I don't have a cite offhand, but I'll hunt around. > I think you have to say DEFPARAMETER if you don't want the compiler to > treat it like a literal constant.
Uck. Is there any good reason for this? It would be really nice to be able to have things who were constant (so could be wired into code) but not immutable, without weird tricks.
* mike...@mikemac.com (Mike McDonald) | So the (hyper) spec uses "constant object" for immutable things. | defconstant doesn't signify that the object is constant, only that using | the binding of the symbol has to be equivilent to using the literal form.
I stand corrected. As atonement, let me collect the relevent texts in one place, demonstrating that the spec does suggest DEFCONSTANT immutability, but that there is room for improvement. (A cynic might think that I'm wryly admitting I'm wrong just to show that I really believe the spec is wrong. A cynic might be right.)
--- There is some question as to whether the values produced by references to DEFCONSTANT are to be treated as literal objects, and are therefore immutable.
Two sections indicate that they are to be immutable:
3.2.2.3 Semantic Constraints:
All conforming programs must obey the following constraints: ... 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.
"constant object" glossary entry
an object that is constrained (e.g., by its context in a program or by the source from which it was obtained) to be immutable. "A literal object that has been processed by compile-file is a constant object."
Unfortunately, DEFCONSTANT has no direct references to either of these entries. In fact, nothing related to DEFCONSTANT seems to reference this "constant object" entry, which itself doesn't even say anything about actually applying to DEFCONSTANT.
Furthermore, some sections suggest suggest though ommision that the value of a constant variable is not a constant object or constant literal, and these sections should probably be ammended:
DEFCONSTANT dictionary entry:
The entry explains in detail the constraints on changing the values of the constant variable produced by defconstant, when the value might be computed, and discusses how the variable may not be bound. However, it never says anything about the value being treated as a literal object, or about references to internal structures of these values.
3.1.2.1.1.3 Constant Variables:
Certain variables, called constant variables, are reserved as "named constants." The consequences are undefined if an attempt is made to assign a value to, or create a binding for a constant variable, except that a `compatible' redefinition of a constant variable using defconstant is permitted; see the macro defconstant.
Note that nothing is said about immutability, nor is there any reference to constant objects or literal objects.
"constant variable" glossary entry:
a variable, the value of which can never change; that is, a keyword[1] or a named constant. ``The symbols t, nil, :direction, and most-positive-fixnum are constant variables.''
Nothing is said about immutability. One could argue either that a value of a variable never changing means that the binding can't change, or alterantively that the internal structure of the value cannot be mutated. (There is also no reference to section 3.1.2.1.1.3, which is a shame.)
"named constant" glossary entry:
a variable that is defined by Common Lisp, by the implementation, or by user code (see the macro defconstant) to always yield the same value when evaluated. "The value of a named constant may not be changed by assignment or by binding."
Again, nothing about immutability or treating the value as a literal object. (Again, no reference to 3.1.2.1.1.3.)
3.2.1 Compiler Terminology:
The term literal object refers to a quoted object or a self-evaluating object or an object that is a substructure of such an object. A constant variable is not itself a literal object.
Because this specifically refers to constant variables, but only in the negative, this could easily be read as indicating that "the value of a reference to a constant variable is not itself a literal object." Apparently, the intention is instead to indicate that the conceptual object called a constant variable (not its value) is not a literal object. However, it is unusual for the spec to refer to the concept of a variable as an object.
"literal" glossary entry:
(of an object) referenced directly in a program rather than being computed by the program; that is, appearing as data in a quote form, or, if the object is a self-evaluating object, appearing as unquoted data.
This definition does not include references to a value defined by DEFCONSTANT.
There is one other source of confusion. Sunil Mishra gives the example that some implementations might treat the values of DEFCONSTANT as compile-file literals, with references in different files being "similar", but not identical. This can lead to confusion. The "workaround" is to use DEFPARAMETER instead, which leads to the embarrassing situation that a user might tend to think of the value of a DEFPARAMETER as more "constant" (really more EQ) across files than the value of a DEFCONSTANT. This confusion is furthered, as David Lamkins points out, by generally understanding "similar" to mean EQL. However, David also points out that the situation only comes up through "programmer error" because it violates the original citation from 3.2.2.3, above. (Any misinterpretatin of Sunil's and David's statements is my fault, not theirs.)
Ultimately, one wonders what is "the right thing." Certainly, one want to allow compilers to treat the value of a constant variable as some kind of compile-time literal so that partial evaluation can be performed at compile time for forms involving references. It comes down to a quesion of whether DEFCONSTANT constrains both implementations to make sure that the value was similar at all times, or just at certain times such as compile and load.
For example, CL already has the issue of what happens when compile time and run time definitions differ. Consider an expression like: (FOO BAR)
If FOO is an an inlinable reference to the function -, and bar is a constant variable with value 1, then the compiler is justified in treating the entire expression as the literal value -1. This is true even if the user latter arranges for FOO to have a different function definition when the above code is actually run. In fact, a different reference to (FOO BAR) in a context in which FOO may not be inlined, must actually call the run time definition of FOO, and might produce a different result.
In other words, we allow the compiler to freeze in the definitions at compile time, while still allowing a function binding to change when referenced in a different context. In the case of function bindings, we're still talking about bindings, not internal structure. (It's another can of worms as to whether there should be a way to turn of the constantness of a defconstant BINDING.) The question here is whether, in the case of DEFCONSTANT, we can allow internal structure changes to be picked up at run time.
My own inclination is that we have other mechanisms for disallowing changes to internal structure -- namely quoting and load-time-value -- which could be used in conjunction with the value-form argument to DEFCONSTANT if desired. Thus, why force defconstant to be a bigger hammer than it needs to be.
In any case, I think it's clear by now that any code that relies on an implementation allowing mutations of value of defconstant will be non-portable, at minimum.