[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Different behaviors of evaluator and compiler
In article <9108211029.AA10023@ub4b.buug.be> %nrb.be%mcsun.EU.net@WARBUCKS.AI.SRI.COM writes:
>Date: Wed, 21 Aug 91 12:25+0100
>From: Vincent Keunen <firstname.lastname@example.org>
>Subject: Different behaviors of evaluator and compiler
>This is a simple function to demonstrate the strange behaviour:
>1(defun test ()
> (let ((result '(nil)))
> (loop for item in '(a b c)
> do (nconc result (list item)))
>(test)0 ;when the function definition is evaluated returns
>1(NIL A B C)0 ;...which is what I want
>1(test)0 ;when the function definition is compiled returns
>2Error: Attempt to RPLACD a list that is embedded in a structure and
>0 2therefore cannot be RPLACD'ed. The list is (NIL)
>0While in the function SYS:RPLACD-ESCAPE SYS:*NCONC TEST
>0 Arg 0 (CONS): (NIL)
> Arg 1 (SI:X): (A)
>s-A, : Editor Top Level
>s-B: Restart process Zmacs Windows
>Can someone help me on this one?
You should initialize result with:
(result (list nil))
NOT (result '(nil)).
Since the tail of result is destructively modified and '(nil) is a constant
embedded in the object code, the second call of (test) will attempt to add to
the end of the previously constructed list. Reasons for this may include that
the list conses have been deallocated or gc'ed.
This is the type of thing you must always look out for when using nconc,
rplaca, rplacd, etc. However, nconc can potentially save a LOT of memory.
Note that '(nil) is ok if you had used append instead of nconc, since append
copies its first argument.
You could also initialize result as (result nil) and use
(setq result (nconc result (list item)))
to build the list.
This form is as efficient, except you have the extra setq, which is quite fast.
Georgia Tech Research Institute, Atlanta, GA, USA