Destructive function on constant data

Discussion of Common Lisp
Post Reply
BIOS
Posts: 15
Joined: Sun Apr 04, 2010 1:55 pm

Destructive function on constant data

Post by BIOS » Fri Jan 14, 2011 10:58 am

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.

:?

vanekl
Posts: 12
Joined: Wed Dec 15, 2010 10:25 am

Re: Destructive function on constant data

Post by vanekl » Fri Jan 14, 2011 11:08 am

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

BIOS
Posts: 15
Joined: Sun Apr 04, 2010 1:55 pm

Re: Destructive function on constant data

Post by BIOS » Fri Jan 14, 2011 11:41 am

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?

vanekl
Posts: 12
Joined: Wed Dec 15, 2010 10:25 am

Re: Destructive function on constant data

Post by vanekl » Fri Jan 14, 2011 11:56 am

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.

BIOS
Posts: 15
Joined: Sun Apr 04, 2010 1:55 pm

Re: Destructive function on constant data

Post by BIOS » Fri Jan 14, 2011 12:13 pm

Sweet. Thanks for the clarification! :D

JamesF
Posts: 98
Joined: Thu Jul 10, 2008 7:14 pm

Re: Destructive function on constant data

Post by JamesF » Sun Jan 16, 2011 3:59 pm

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.

Jasper
Posts: 209
Joined: Fri Oct 10, 2008 8:22 am
Location: Eindhoven, The Netherlands
Contact:

Re: Destructive function on constant data

Post by Jasper » Tue Jan 18, 2011 2:17 pm

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.

nuntius
Posts: 538
Joined: Sat Aug 09, 2008 10:44 am
Location: Newton, MA

Re: Destructive function on constant data

Post by nuntius » Tue Jan 18, 2011 7:22 pm

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.

Post Reply