(constant 'x) broken?

Started by gregben, March 10, 2004, 02:28:41 PM

Previous topic - Next topic

gregben

I tried the following using 7.5.0 on both Solaris and WIN32:





> (set 'a 3)

3

> (dec 'a)

2

> (constant 'a)

2

> (dec 'a)

1

> (set 'a 5)

symbol is protected in function set : a

> a

1





It appears that the (constant 'a) call only

protects against (set) but not (dec) or (inc)

for that matter. This doesn't conform to my

idea of a constant. I would expect (constant 'a)

to "lock"  the variable a from any further alteration.

Lutz

#1
Thanks for catching this problem, this will be corrceted in the next deveopment release 7.5.9, due next week.



Lutz

eddier

#2
Thanks for catching this one! I've been trying to figure out what was wrong with one of my cgi programs for a while now. It would only fail now and then, turns out it was the constant function.



Eddie

nigelbrown

#3
This raises the issue of 'what is it that is constant?'

consider



> (constant 's "string")

"string"

> (set-nth 3 s "xxx")

"strxxxng"

> (setq s "another")



symbol is protected in function setq : s



>



and



> (constant 'a '(a b c))

(a b c)

> (push 'd a)

d

> a

(d a b c)

> (setq a '( "some" "other" "list"))



symbol is protected in function setq : a



>



In each case the constancy is that the symbol refers to the same object but with push and set-nth that object's structure can be changed. By analogy

in

> (constant 'a 3)

3

> (inc 'a)

4

> (setq a 25)



symbol is protected in function setq : a



>



inc (like push and set-nth) is allowed to play with the referenced object (in this case an integer word) but set or setq can't point the symbol at some other object.



What do we want constant?

Lutz

#4
I would say all of these are bugs!  (all destructive functions?)



'constant' should mean that the contents of a symbol cannot be changed except using another 'constant' statement, or like is says int the menual:



"constant ... protects the symbol from subsequent modification"



'constant' was introduced in version 6.5.27 ! but nobody (including the one who introduced it ;) ) ever used it much.



I am glad bugs around 'constant' are surfacing now and I can fix them before 8.0. I think that 'constant' is an important function when doing newLISP projects by more than one programmer. That was the thinking when it was introduced.



Lutz

nigelbrown

#5
I wondered 'How does Common Lisp (CL) do constants?'.



From Common Lisp the Language 2nd ed (CLTL2):

"[Function]

constantp object



If the predicate constantp is true of an object, then that object, when considered as a form to be evaluated, always evaluates to the same thing; it is a constant. This includes self-evaluating objects such as numbers, characters, strings, bit-vectors, and keywords, as well as all constant symbols declared by defconstant, such as nil, t, and pi. In addition, a list whose car is quote, such as (quote foo), is considered to be a constant.



If constantp is false of an object, then that object, considered as a form, might or might not always evaluate to the same thing."



That is list even if unchanged may evaluate differently

- even in newLISP viz:

> (constant 'funct '(dosomething))

(dosomething)

> (define (dosomething) (+ 2 3 4))

(lambda () (+ 2 3 4))

> (eval funct)

9

> funct

(dosomething)

> (define (dosomething) (- 1000 99))

(lambda () (- 1000 99))

> (eval funct)

901

> (set 'funct '(somethingelse))



symbol is protected in function set : funct



>



further from Common Lisp Hyperspec:

"Macro DEFCONSTANT



Syntax:

defconstant name initial-value [documentation] => name



Arguments and Values:

name---a symbol; not evaluated.

initial-value---a form; evaluated.

documentation---a string; not evaluated.





Description:

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



A constant defined by defconstant can be redefined with defconstant. 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.



If documentation is supplied, it is attached to name as a documentation string of kind variable.



defconstant normally appears as a top level form, but it is meaningful for it to appear as a non-top-level form. However, the compile-time side effects described below only take place when defconstant appears as a top level form.



The consequences are undefined if there are any bindings of the variable named by name at the time defconstant is executed or if the value is not eql to the value of initial-value.



The consequences are undefined when constant symbols are rebound as either lexical or dynamic variables. In other words, a reference to a symbol declared with defconstant always refers to its global value.



The side effects of the execution of defconstant must be equivalent to at least the side effects of the execution of the following code:





 (setf (symbol-value 'name) initial-value)

 (setf (documentation 'name 'variable) 'documentation)



If a defconstant form appears as a top level form, the compiler must recognize that name names a constant variable. 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. "



I note the bit "However, the consequences are undefined if an attempt is made to assign a value to the symbol using another operator" that is most relevant to our newlisp discussions - this suggests that whether a defconstant constant in CL can be modified by destructive functions is ?implementation dependent.

Testing on CLISP and Corman Lisp shows that trying (incf a) after (defconstant a 24) fails viz in CLISP:



[1]> (defconstant a 22)

A

[2]> a

22

[3]> (incf a)



*** - SETQ: the value of the constant A may not be altered

1. Break [4]>



However incf is a macro which does:

"The delta is added to (in the case of incf) or subtracted from (in the case of decf) the number in place and the result is stored in place. "

so a 'store' is actually attempted.



They will allow modification of a defconstant list by setf'ing into it viz CLISP:



[1]> (defconstant a '(a b c))

A

[2]> a

(A B C)

[3]> (setf (nth 1 a) 'd)

D

[4]> a

(A D C)

[5]>



Tricky things these constants!

As newdep might say -- (define? (constant))