From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Nicolas Richard Newsgroups: gmane.emacs.tangents Subject: Re: 2016-05-23 Emacs News Date: Fri, 10 Jun 2016 16:55:45 +0200 Message-ID: <87lh2dgkjy.fsf@ulb.ac.be> References: <87lh30iv18.fsf@sachachua.com> <87bn39ewp6.fsf@linux-qg7d.fritz.box> <87twh1gwu8.fsf@members.fsf.org> <8737oldv21.fsf@linux-qg7d.fritz.box> 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 1465570797 7207 80.91.229.3 (10 Jun 2016 14:59:57 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 10 Jun 2016 14:59:57 +0000 (UTC) Cc: emacs-tangents@gnu.org To: Rolf Ade Original-X-From: emacs-tangents-bounces+get-emacs-tangents=m.gmane.org@gnu.org Fri Jun 10 16:59:48 2016 Return-path: Envelope-to: get-emacs-tangents@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 1bBNuV-0002pH-Kg for get-emacs-tangents@m.gmane.org; Fri, 10 Jun 2016 16:59:47 +0200 Original-Received: from localhost ([::1]:41767 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bBNuU-0001jU-V8 for get-emacs-tangents@m.gmane.org; Fri, 10 Jun 2016 10:59:46 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:55801) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bBNqB-0007tU-5i for emacs-tangents@gnu.org; Fri, 10 Jun 2016 10:55:20 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bBNq6-00054m-06 for emacs-tangents@gnu.org; Fri, 10 Jun 2016 10:55:18 -0400 Original-Received: from mxinc360.ulb.ac.be ([164.15.128.112]:44770 helo=mxin.ulb.ac.be) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bBNq5-00054c-NG for emacs-tangents@gnu.org; Fri, 10 Jun 2016 10:55:13 -0400 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AiEFAEgeUlekD4Xx/2dsb2JhbABegmiCJYJ2oywBAQEBCJYxhhICggABAQEBAQFmJ4RGAQEEIw8BRhAIAxoCBSECAg8BRwYTGogVsU2RGQEBCAIBJIEBhF6FFYE5hgiCWQWTOIUNkA2ET4J7MYU4NY8dVIIHDQ+BTToyihIBAQE Original-Received: from mathsrv4.ulb.ac.be (HELO localhost) ([164.15.133.241]) by smtp.ulb.ac.be with ESMTP/TLS/AES128-SHA; 10 Jun 2016 16:55:12 +0200 User-agent: mu4e 0.9.17; emacs 25.0.92.1 In-reply-to: <8737oldv21.fsf@linux-qg7d.fritz.box> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 164.15.128.112 X-BeenThere: emacs-tangents@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-tangents-bounces+get-emacs-tangents=m.gmane.org@gnu.org Original-Sender: "Emacs-tangents" Xref: news.gmane.org gmane.emacs.tangents:133 Archived-At: Rolf Ade writes: > Is what the article demonstrates something special to the 'build-in' > function sort or to emacs lisp? It would help me, if someone explains > what happen in this example in other words (not in implementation detail > but language concepts). Note : meanwhile I saw Marcin posted a much shorter re-explanation... oh well, I'll just post this anyway :) I can't really do it in language-concepts because I don't know which concepts you're familiar with, and more importantly because *I* am not familiar enough with the concepts. I still hope it will be helpful : It's related to two facts: (i) sort changes the list inplace. (ii) the list is built at read-time instead of call-time, so that calling the same function multiple times re-uses the same list. Now the steps that show the "problem". I'll try to explain very slowly. I hope this is not too much details. A) lisp code is actually a lisp list. In our example, the code that defines destructive-havoc is this : (defun destructive-havoc () "Example of destructive havoc." (setq foo '(1 3 2)) (message "before sort, foo is: %s" foo) (sort foo #'<) (message "after sort, foo is: %s" foo)) That clearly looks like a list (first element would be the symbol `defun`, then the symbol `destructive`, then the empty list aka symbol `nil`, then a string, then four more lists). When you want to eval this code, emacs will first turn this list-looking-thing-in-your-buffer into an actual Lisp list. This is the reading step, aka read-time. Two more things to note in this step : - when emacs read '(1 3 2), it turned it into (quote (1 3 2)). This is what ' means. So this is in fact a list made of the symbol quote and the list (1 3 2). This list (1 3 2), I'll call it FooBar. - if you read the docstring of `quote`, it mentions something about « the value that was pre-constructed by the Lisp reader » and what it refers to, is exactly the FooBar list. But quote is not doing its job right now, so I'll come back to that later. B) Since we asked, emacs will now proceed to evaluating this big list. This is what I called "call-time". How it does it is described in (info "(elisp) Intro Eval"), but basically it first looks at the first element of the list, and then decides what to do with the rest of the list. In this case the first element is `defun`, which is a symbol which denotes a macro, thus emacs will expand the macro and do its thing. At the end of this step, emacs now turned the symbol `destructive-havoc` into a function which holds the following list as its definition: (lambda nil "Example of destructive havoc." (setq foo (quote (1 3 2))) (message "before sort, foo is: %s" foo) (sort foo (function <)) (message "after sort, foo is: %s" foo)) Here, note that a part of this list is in fact the bit that was created in step A, namely everything from (setq ... until the last paren. In particular, the (1 3 2) list in there is our FooBar. C) next thing you'll be doing is evaluate (destructive-havoc). Again, emacs will read first (like step A) then evaluate (like step B) this code. This time, when evaluating, emacs sees destructive-havoc is symbol with a function definition, which means it'll evaluate the list contained in that function, i.e. the (lambda ...) form we have mentionned previously. Evaluating this lambda essentially means to evaluate all elements of the code inside, which is those : (setq foo (quote (1 3 2))) (message "before sort, foo is: %s" foo) (sort foo (function <)) (message "after sort, foo is: %s" foo) C1) The first thing is the setq, which gives `foo' the value obtained from evaluating (quote (1 3 2)). At this point, evaluating (quote (1 3 2)) returns the value pre-constructed by the lisp reader in step A at the very beginning, which is FooBar. C2) message constructs a string and shows it in the *Messages* buffer. C3) sort sorts in-place, thus changing the data. IOW, FooBar was (1 3 2) but is now (1 2 3). It's the same list, but its content was changed. C4) message constructs a string and shows it in the *Messages* buffer. *at this point in time*, since the function definition contained FooBar and FooBar has had its content changed, the function inside destructive-havoc has somehow... changed too. It didn't change, really, but its content changed. D) if you re-evaluate (destructive-havoc), the same steps happen again, but since FooBar is now (1 2 3), what you see at step D2 is different. Please note that despite the rather long post, I left out some details, in particular (i) the difference between macro (or special form) and function, (ii) the actual implementation of lists (as cons cells), (iii) the byte-compilation and eager macro-expansion that might actually happen when you evaluate things manually, even though you did not request them. HTH anyway. -- Nicolas