bug-gnu-emacs
[Top][All Lists]
Advanced

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

Re: Futile bug reports?


From: Bill Richter
Subject: Re: Futile bug reports?
Date: 17 Aug 2001 21:59:39 -0500
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.0.104

>>>>> Raymond Zeitler <rayz@phonon.com.invalid> responds to me:

  >> If someone gets interested in Emacs Lisp, I'll tell them they
  >> should read a Scheme book like SICP by Abelson or `How to Design
  >> Programs' by Felleisen [HTDP], and then the Emacs Lisp reference
  >> manual will make sense to them.  I can't see how anyone could
  >> understand the Emacs Lisp reference manual without having prior
  >> knowledge of Scheme/Lisp.
  >> 

  Ray> That why there's Introduction to Programming in Emacs Lisp, by
  Ray> Robert J. Chassell.  Even I can understand it.  :-)

Thanks, Ray, I just re-read the parts on pointers.  I don't think it's
a very good description, and I think the users will need SICP or
HTDP.  Punchline right up top:

Chassell says a lot about pointers that are unnecessary (`setq'
assigns a variable to a pointer to the Lisp object that a naive user
would have thought it was assigned to), and skips the part of pointers
that are needed by intro users: the shared structure properties of
lists, given by the properties of setc*r.

Let's quote from Chassell a few times, I got by `s-ing' for
[^-]pointer.  I'm very curious if "even you" already understood the
stuff I'm hammering through below.

>From the Emacs Lisp Intro info node "Using setq":


   Although I have been using the term `assign', there is another way
   of thinking about the workings of `set' and `setq'; and that is to
   say that `set' and `setq' make the symbol _point_ to the list.
   THIS LATTER WAY OF THINKING IS VERY COMMON and in forthcoming
   chapters we shall come upon at least one symbol that has `pointer'
   as part of its name.  The name is chosen because the symbol has a
   value, specifically a list, attached to it; or, expressed in this
   other way, the symbol is set to "point" to the list.

In order to understand this LATTER WAY OF THINKING which IS VERY
COMMON, the reader should read some longer Scheme texts, such as SICP
or HTDP.  In particular, the reader should learn that this VERY COMMON
WAY OF THINKING is not actually required in order to understand
Lisp/Scheme evaluation.  In my opinion, this extra layer of pointers
is just a confusion for the user, it may well be a good optimization.

That is, it's not necessary to believe that (setq x foo) binds x to a
pointer which points to the value of foo.  

There is a *real* need for pointers, explained in the Emacs Lisp Intro
info node "List Implementation":

   A list is kept using a series of pairs of pointers.  In the series,
   the first pointer in each pair points to an atom or to another
   list, and the second pointer in each pair points to the next pair,
   or to the symbol `nil', which marks the end of the list.

   A pointer itself is quite simply the electronic address of what is
   pointed to.  Hence, a list is kept as a series of electronic
   addresses.

That's good stuff, not clearly explained in the Emacs Lisp reference
manual.  However, Chassell slips into the same confusion that's in the
Emacs Lisp reference manual:

   In the diagram, each box represents a word of computer memory that
   HOLDS a Lisp object, usually in the form of a memory address.

I find this very confusing, if not false.  I would write this as

   In the diagram, each box contains a pointer to a Lisp object.

   In the diagram, each box represents a word of computer memory that
   HOLDS the address of a Lisp object.

The phrases "points to" and "hold" are being confused, I don't like
that.  This confusion persists, and pervades the Emacs Lisp reference
manual.

I dislike the clause "usually in the form of a memory address",
because it refers to the above doctrine that every Lisp object is
really a pointer to what you thought the Lisp object was.  I agree
that THIS LATTER WAY OF THINKING IS VERY COMMON, but an intro reader
doesn't need to hear it.  Continuing through the Emacs Lisp Intro info
node "List Implementation":


     (setq bouquet '(rose violet buttercup))

   creates a situation like this:

     bouquet
          |
          |     ___ ___      ___ ___      ___ ___
           --> |___|___|--> |___|___|--> |___|___|--> nil
                 |            |            |
                 |            |            |
                  --> rose     --> violet   --> buttercup

   In this case, the symbol `bouquet' holds the address of the first
   pair of boxes.  Indeed, the symbol `bouquet' consists of a group of
   address-boxes, one of which is the address of the printed word
   `bouquet', a second of which is the address of a function
   definition attached to the symbol, if any, a third of which is the
   address of the first pair of address-boxes for the list `(rose
   violet buttercup)', and so on.

I would say that "hold" is used correctly here, but that it's
needlessly confusing.  It would be simpler to say that

   bouquet is assigned to a list which consists basically of 4
   pointers: 4 memory addresses containing the locations of the
   symbols rose violet buttercup and the Lisp object nil.

There's no reason for an intro to be explaining the doctrine under
which bouquet is bound to a pointer to the list, rather than the list
itself.  intro readers need to know that the list is not the ordered
triple (rose, violet, buttercup), but a triple of pointers (p, q, r),
whose dereferences are rose, violet, buttercup, in psuedo-C jive:

*p => rose
*q => violet
*r => buttercup

Continuing through the Emacs Lisp Intro info node "List
Implementation", I'd say hold was used correctly below, but again it's
unnecessary:

   In an earlier section, I suggested that you might imagine a symbol
   as being a chest of drawers.  The function definition is put in one
   drawer, the value in another, and so on.  What is put in the drawer
   *holding* the value can be changed without affecting the contents
   of the drawer *holding* the function definition, and vice-versa.
   Actually, what is put in each drawer is the address of the value or
   function definition.  It is as if you found an old chest in the
   attic, and in one of its drawers you found a map giving you
   directions to where the buried treasure lies.


Continuing through the Emacs Lisp Intro info node "List
Implementation", we get to

     (setq flowers (cdr bouquet))

   produces this:


     bouquet        flowers
       |              |
       |     ___ ___  |     ___ ___      ___ ___
        --> |   |   |  --> |   |   |    |   |   |
            |___|___|----> |___|___|--> |___|___|--> nil
              |              |            |
              |              |            |
               --> rose       --> violet   --> buttercup



   The value of `flowers' is `(violet buttercup)', which is to say,
   the symbol `flowers' holds the address of the pair of
   address-boxes, the first of which holds the address of `violet',
   and the second of which holds the address of `buttercup'.

I'd say that hold was used correctly here, but again it's an
unnecessary layer of pointers.  I'd say this as 

                            flowers
                              ||             
                              ||             
             ___ ___        ___ ___      ___ ___
bouquet  =  |   |   |      |   |   |    |   |   |
            |___|___|----> |___|___|--> |___|___|--> nil
              |              |            |
              |              |            |
               --> rose       --> violet   --> buttercup



   The value of `flowers' is `(violet buttercup)', which is to say,
   the symbol `flowers' is assigned to the pair of address-boxes, the
   first of which holds the address of `violet', and the second of
   which holds the address of `buttercup'.

And maybe you're wondering, why do we need *any* pointers?  The reason
is setcar/setcdr.  But there's no discussion of pointers in the Emacs
Lisp Intro info nodes "setcar" and "setcdr", the one place the
discussion is needed!!!  Here's the important feature, not explained
in these nodes "setcar" and "setcdr" at all:

(setq x '(1))
=> (1)

(setq y x)
=> (1)

(setcar x 6)
=> 6

(car y)
=> 6

When I first realized this feature, I was floored.  I thought wait,
`(car y)' should still return 1.  That's what does happen here:

(setq x 1)
=> 1
(setq y x)
=> 1
(setq x 6)
=> 6
y
=> 1

(That's one reason I hate the slogan that x and y are assigned to
pointers which point to 1 & 6.)

But the quite different behavior with cons/setcar is easily explained
by the pointer jive:

(setq x '(1))

essentially assigns x to a pointer, and performs the C assignment

*x = 1;

Then y is assigned to x, in C that would be 

y = x;

meaning that the value of y is a the same memory location whose value
x is.    Then we perform 

*x = 6

which doesn't change y at all, but it changes the value of *y to 6.  

Nothing wrong with the box 'n pointer picture for this


             ___ ___ 
y  =  x  =  |   |   |
            |___|___| --> nil
              |      
              |      
               --> 1 


which clearly seems to show that changing the car of x to 6 just
changes the box 'n pointer picture to


             ___ ___ 
y  =  x  =  |   |   |
            |___|___| --> nil
              |      
              |      
               --> 6

so  

(car y)
=> 6

That's the whole point of pointers in Scheme/Lisp, AFAIK.  Usually
this feature is called "shared structure" (a phrase not used in
Chassell's intro), and is explained in the Emacs Lisp reference
manual, in info node "Setcar":

   When a cons cell is part of the shared structure of several lists,
   storing a new CAR into the cons changes one element of each of
   these lists.  Here is an example:

     ;; Create two lists that are partly shared.
     (setq x1 '(a b c))
          => (a b c)
     (setq x2 (cons 'z (cdr x1)))
          => (z b c)
     
     ;; Replace the CAR of a shared link.
     (setcar (cdr x1) 'foo)
          => foo
     x1                           ; Both lists are changed.
          => (a foo c)
     x2
          => (z foo c)
     
     ;; Replace the CAR of a link that is not shared.
     (setcar x1 'baz)
          => baz
     x1                           ; Only one list is changed.
          => (baz foo c)
     x2
          => (z foo c)

   Here is a graphical depiction of the shared structure of the two
lists in the variables `x1' and `x2', showing why replacing `b' changes
them both:

             --- ---        --- ---      --- ---
     x1---> |   |   |----> |   |   |--> |   |   |--> nil
             --- ---        --- ---      --- ---
              |        -->   |            |
              |       |      |            |
               --> a  |       --> b        --> c
                      |
            --- ---   |
     x2--> |   |   |--
            --- ---
             |
             |
              --> z



Here is an alternative form of box diagram, showing the same
relationship:

     x1:
      --------------       --------------       --------------
     | car   | cdr  |     | car   | cdr  |     | car   | cdr  |
     |   a   |   o------->|   b   |   o------->|   c   |  nil |
     |       |      |  -->|       |      |     |       |      |
      --------------  |    --------------       --------------
                      |
     x2:              |
      --------------  |
     | car   | cdr  | |
     |   z   |   o----
     |       |      |
      --------------


Here is an alternative form of box diagram, showing the same
relationship:

     x1:
      --------------       --------------       --------------
     | car   | cdr  |     | car   | cdr  |     | car   | cdr  |
     |   a   |   o------->|   b   |   o------->|   c   |  nil |
     |       |      |  -->|       |      |     |       |      |
      --------------  |    --------------       --------------
                      |
     x2:              |
      --------------  |
     | car   | cdr  | |
     |   z   |   o----
     |       |      |
      --------------


I don't like this picture at all, since it blurs the distinction
between holding a value and pointing to a value.   The previous
diagram had more arrows than  necessary.  Here's my picture:
        a                     b (then foo)         c
        ^                     ^                    ^
        |                     |                    |
      --|-----------       ---|----------       ---|----------
     |  |    |      |     |   |   |      |     |   |   |      |
x1 = |  o    |   o------->|   o   |   o------->|   o   |  o------> nil
     |       |      |     |       |      |     |       |      |
      --------------       --------------       --------------
                                  ^      
                                  |     
                       -----------|--  
                      |       |   |  | 
                 x2 = |   o   |   o  |
                      |   |   |      |
                       ---|----------
                          |
                          V
                          z

or the psuedo-C jive works just as well.  The 1st 2 assignments 

     (setq x1 '(a b c))
     (setq x2 (cons 'z (cdr x1)))

amount to creating 4 pointers p,q,r & s and then assigning them as

x1 = (p,q,r) 
*p = a
*q = b
*r = c
x2 = (s,q,r) 
*s = z 

and 

     (setcar (cdr x1) 'foo)
     (setcar x1 'baz)

amounts to 

*q = foo
*p = baz

and clearly the 1st assignment changes x2 (or should I say *x2), but
the 2nd assignment does not.

-- 
Bill <http://www.math.nwu.edu/~richter>



reply via email to

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