emacs-tangents
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 2016-05-23 Emacs News


From: Nicolas Richard
Subject: Re: 2016-05-23 Emacs News
Date: Fri, 10 Jun 2016 16:55:45 +0200
User-agent: mu4e 0.9.17; emacs 25.0.92.1

Rolf Ade <address@hidden> 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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]