Subject: Re: Please help
From: Erik Naggum <>
Date: 1999/04/08
Newsgroups: comp.lang.lisp
Message-ID: <>

* Lieven Marchand
| (let ((acc nil))
|    (dolist (.....)
|       ......
|       (push item acc))
|    (nreverse acc))

* "Christopher J. Vogt" <>
| Gack!  I hope nobody is really using such an idiom, push/reverse is
| unnecessary, and awfully inefficient.

  how did "actually faster" get contorted into "awfully inefficient"?  you
  have never tried to profile code like this, have you?

| I'm a loop user not a do user so I can't give the code for doing this
| using do, but using loop:
| (loop for item from 1 to 10
|       collect item)
| which is no doubt desctructive, keeping a pointer to the end of the list
| and using rplacd to add to the end of the list.

  sigh.  you just made it harder for me to defend using LOOP.  but at least
  I know how to do it, which is why I prefer that LOOP do it for me...

  SETF of CDR (or RPLACD if you insist) is a destructive operation, and
  this has GC implications.  PUSH does not have GC implications.  the idiom
  is (setf foo (setf (cdr foo) (cons bar nil))), and as you should be able
  to see, this involves more work than (setf foo (cons bar foo)).

  also note that it is unspecified whether NREVERSE does its work by CARs
  or by CDRs.  both have interesting performance characteristics.

  note, however, that if you can convince the compiler to cons on the stack
  (a.k.a., dynamic-extent), and not on the heap, REVERSE at the end might
  be more efficient, since it can take advantage of the stack organization.
  this, however, would require compiler recognition of this particular
  idiom, and probably a waste of time to a vendor.  so expect free software
  to sport such an optimization opportunity.  ;)