From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: "Pascal J. Bourguignon" Newsgroups: gmane.emacs.help Subject: Re: `append' vs. `nconc' Date: Wed, 30 Dec 2015 17:18:32 +0100 Organization: Informatimago Message-ID: <87bn97ewpz.fsf@kuiper.lan.informatimago.com> References: <568164D8.6050700@ojkastl.de> <87io3iyr7t.fsf@debian.uxu> <87si2kezg1.fsf@mithlond.arda> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Trace: ger.gmane.org 1451492425 8649 80.91.229.3 (30 Dec 2015 16:20:25 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 30 Dec 2015 16:20:25 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Wed Dec 30 17:20:20 2015 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1aEJU3-0002ZU-Jn for geh-help-gnu-emacs@m.gmane.org; Wed, 30 Dec 2015 17:20:19 +0100 Original-Received: from localhost ([::1]:52942 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aEJU2-0007nj-Si for geh-help-gnu-emacs@m.gmane.org; Wed, 30 Dec 2015 11:20:18 -0500 Original-Path: usenet.stanford.edu!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail Original-Newsgroups: gnu.emacs.help Original-Lines: 90 Original-X-Trace: individual.net tzi3t8cn7OzKpPLz/jw8PAndrJaVARGUcIB93cAnip+b9U7VEG Cancel-Lock: sha1:NzFkMDBjODFjZTdmMTk5NWI4NTJmMzAwNzJhNjMzYzlkMWI2NGVkMg== sha1:pebtmQWU6VCQporRDWZ2GqFB2f4= Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) Original-Xref: usenet.stanford.edu gnu.emacs.help:216237 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:108527 Archived-At: Emanuel Berg writes: > Teemu Likonen writes: > >> There you create a list MODES and then APPEND copies >> the whole list and joins it to AUTO-MODE-ALIST. >> The original list is discarded. No problem, it's >> just a configuration code. But in some other >> situation it might be good idea to construct the >> list only once and use NCONC which only traverses >> the lists through and modifies last conses to join >> it to the next list: >> >> (let ((modes (list '(a . b) ;; ... ))) (setq >> auto-mode-alist (nconc modes auto-mode-alist))) > > So what you are saying, if `append' is replaced by > `nconc', the same thing happens, only one less list > has to be created? > > I have several appends in my source, is there > a rule-of-thumb when to use `append' and when to use > `nconc'? In doubt, use append. If you are appending freshly consed lists, then it's safe to use nconc. For example: (defun f (lists) (loop for list in lists append list)) (defun f* (lists) (apply (function append) lists)) (defun g (lists) (loop for list in lists nconc (mapcar (function 1+) list))) In f, we are appending lists that are given to the function in the parameter. Since we don't know whether those lists will be shared or literal (we didn't specify anything about the lists), we should avoid mutating them, therefore we use append in f. A new copy of each of the list will be used to build the result. Notice that in f*, append does not copy the last list. We obtain a result that shares structure with the arguments. This may be a problem or not, but in any case, that means that the result of f* is not a fresh list, even if most of it is made of new cons cells, because of this shared tail! When you have a fixed set of lists to append, you can either use concatenate, or add a '() as last argument to append: (concatenate 'list l1 l2 l3) --> a fresh list (append l1 l2 l3 '()) --> a fresh list (append l1 l2 l3) --> a list sharing structure with l3. In the case of g, since we create new lists (by way of mapcar), there are no other reference to those lists, so we can use nconc, mutating their last cdr to concatenate them without having to copy them. Another way to say it: if you could use sort on your lists without copy-list, then you can use nconc, otherwise you should use append: (let ((l (list 1 2 3)) s) (list (setf s (sort l '<)) ; ok (nconc s (list 4 5 6)))) ; ==> nconc ok (let ((l '(1 2 3)) s) (list (setf s (sort (copy-list l) '<)) ; copy-list needed (append l (list 4 5 6)) ; ==> use append (nconc s (list 4 5 6)))) ; s is a fresh copy ==> nconc ok -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk