Page 1 of 1

Destructive function on constant data

Posted: Fri Jan 14, 2011 10:58 am
by BIOS
Can anyone tell me what I'm doing wrong here:

Code: Select all

(let* ((x '(1 2 3 4 5))
		(y))
	   
	   (setf y (nreverse x)))
I just want to set one variable as the reverse list of the other but i get the following error:

; in: LAMBDA NIL
; (NREVERSE X)
;
; caught WARNING:
; Destructive function NREVERSE called on constant data.

:?

Re: Destructive function on constant data

Posted: Fri Jan 14, 2011 11:08 am
by vanekl
Some versions of lisp don't allow you to destructively modify what it considers constant data when you use a quote.
Try this instead:

Code: Select all

(let ((x (list 1 2 3 4 5))
       y)
  (setf y (nreverse x))
  (values y x))

Re: Destructive function on constant data

Posted: Fri Jan 14, 2011 11:41 am
by BIOS
Hey thanks for the reply. Yep your code works fine. As does this i found out:

Code: Select all

(let* ((x '(1 2 3 4 5))
		(y))
	   (setf y (reverse x)))
Which indicates the issue lies with the nreverse function?

Re: Destructive function on constant data

Posted: Fri Jan 14, 2011 11:56 am
by vanekl
It's a combination of quote and nreverse. Nreverse tries to destructively change x in some versions of lisp, but it cannot because the quote makes x constant. On the other hand, 'reverse' makes a copy of x and doesn't try to change x, so no error.

Re: Destructive function on constant data

Posted: Fri Jan 14, 2011 12:13 pm
by BIOS
Sweet. Thanks for the clarification! :D

Re: Destructive function on constant data

Posted: Sun Jan 16, 2011 3:59 pm
by JamesF
BIOS wrote:Can anyone tell me what I'm doing wrong here:

Code: Select all

(let* ((x '(1 2 3 4 5))
		(y))
	   
	   (setf y (nreverse x)))
This smells like C-style thinking. Why not this?

Code: Select all

(let* ((x '(1 2 3 4 5))
		(y (reverse x)))
You'd actually need let* in this case, whereas let is sufficient in your original snippet, where it doesn't matter which order the bindings for x and y are evaluated.

Re: Destructive function on constant data

Posted: Tue Jan 18, 2011 2:17 pm
by Jasper
Afaik QUOTE does not make x constant, quote make the variable x point to a list '(1 2 3 4 5), but that list is *not* created when you call it, it is always there. So if you do:

Code: Select all

(defun quote-abuse ()
  (let ((list '(1 2 3 4 5)))
    list))

(setf (car (quote-abuse)) 'unexpected)

(quote-abuse) ;=> (unexpected 2 3 4 5)
I guess the effect is that one should treat it as a constant,(which why it warns) but it isn't really.

Re: Destructive function on constant data

Posted: Tue Jan 18, 2011 7:22 pm
by nuntius
For some odd reason, I love comparing CL to C.

In C, the expression char *x="some string"; doesn't inherently mean that "some string" is a constant. However, there are efficiency gains from making it so; and string literals are now constant by mandate/standardization. (Modifying a string literal invokes "undefined behavior" -- meaning don't do that. Some compilers put them in read-only memory; thus a write will cause a memory fault.)

Same thing goes for quoted list literals in CL.