emacs-devel
[Top][All Lists]
Advanced

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

`setplist' on local var escaping let binding


From: MON KEY
Subject: `setplist' on local var escaping let binding
Date: Wed, 20 Oct 2010 19:28:17 -0400

I noticed today that if I `setplist' on a null let bound local var
inside a call to `with-current-buffer' the symbol's property list can
escape the scope of the let binding. This happens in one case but not
in another.  I can't figure out why.

Does elisp treat a symbol's plist as a global resource distinct from
its value cell?

The Common Lisp ANSI spec has this to say w/re `symbol-plist':

,----
| The use of `setf' should be avoided, since a symbol's property list
| is a global resource that can contain information established and
| depended upon by unrelated programs in the same Lisp image.
`----

I reviewed the Emacs Lisp specification :P for a similarly equivalent
cautionary missive but I still can't tell if this is a bug or not.

So, I'm asking here.

Following is an attempt at illustrating what is happening:

(progn
  (unintern "local-var" obarray)
  (let (local-var)
    (with-temp-buffer
      (setplist 'local-var '(prop1 1 prop2 2 prop3 3))
      (symbol-plist 'local-var))))
;=> (prop1 1 prop2 2 prop3 3)

> (symbol-plist 'local-var)
;=> nil

Now unintern the `local-var' symbol:

(unintern "local-var" obarray)
;=> t

Following expression also puts properties on `local-var', but this
time its properties "escape" the let-binding:

(progn
  (ignore)
  (let (local-var)
    (with-temp-buffer
      (setplist 'local-var '(prop1 1 prop2 2 prop3 3))
      (symbol-plist 'local-var))))
;=> (prop1 1 prop2 2 prop3 3)

(symbol-plist 'local-var)
;=> (prop1 1 prop2 2 prop3 3)

This seems either wrong or inconsisistent because `local-var' was
well... local. I would expect the symbol-plist to also return nil
outside the let binding as it did in the first example.

I thought maybe the issue was around `with-temp-buffer' so I tried this:

(with-current-buffer
    (get-buffer-create "*fresh-buffer-for-local-var*")
  (progn
    (unintern "local-var" obarray)
    (let (local-var)
      (with-temp-buffer
        (setplist 'local-var '(prop1 1 prop2 2 prop3 3))
        (symbol-plist 'local-var)))))
;=> (prop1 1 prop2 2 prop3 3)

(symbol-plist 'local-var)
;=> nil

To mimic `with-temp-buffer' macro rid the "temp-buffer" w/:

(kill-buffer (get-buffer-create "*fresh-buffer-for-local-var*"))

Also, to meake sure that `local-var' is really dead:
(unintern "local-var" obarray)

Trying the same, but without uninterning `local-var' inside `progn':

(with-current-buffer
    (get-buffer-create "*fresh-buffer-for-local-var*")
  (progn
    (ignore)
    (let (local-var)
      (with-temp-buffer
        (setplist 'local-var '(prop1 1 prop2 2 prop3 3))
        (symbol-plist 'local-var)))))
;=> (prop1 1 prop2 2 prop3 3)

(symbol-plist 'local-var)
;=> (prop1 1 prop2 2 prop3 3)

Now without the `progn' wrapper but keeping the `unintern':

(with-current-buffer
    (get-buffer-create "*fresh-buffer-for-local-var*")
  (unintern "local-var" obarray)
  (let (local-var)
    (with-temp-buffer
      (setplist 'local-var '(prop1 1 prop2 2 prop3 3))
      (symbol-plist 'local-var))))
;=> (prop1 1 prop2 2 prop3 3)

(symbol-plist 'local-var)
;=> nil

Again, just to be sure, rid any possibility that `local-var' is
lingering in some unseen Emacs crevice:

(kill-buffer (get-buffer-create "*fresh-buffer-for-local-var*"))
(unintern "local-var" obarray)

Now, without the `progn' wrapper and without the `unintern':

(with-current-buffer
    (get-buffer-create "*fresh-buffer-for-local-var*")
  (let (local-var)
    (with-temp-buffer
      (setplist 'local-var '(prop1 1 prop2 2 prop3 3))
      (symbol-plist 'local-var))))
;=> (prop1 1 prop2 2 prop3 3)

(symbol-plist 'local-var)
;=> (prop1 1 prop2 2 prop3 3)

I've verified the above behavior w/ emacs -Q

(emacs-version)
;=> "GNU Emacs 23.2.1 (i686-pc-linux-gnu, GTK+ Version 2.20.0)
;    of 2010-05-10"

It seems fair to assume that neither the special form `progn' nor the
macro `with-temp-buffer' are causing the divergent behavior.

So, what gives?

Is there something happening around forms containing `unintern'/`let'
which allow a null symbols's plist to return to nil whereas it
otherwise won't?

And, more specifically what is the correct behavior?

Is it expected that every interned symbol's plist should have global
extent independent of its scope?

I ask because I'm interested to learn how this may affect the
proposed integration of the lexbind?

If what I have pointed out above is some sort of bug (abstract though
it may be) my suspicion is that the "problem" originates with the
priveleged space Emacs' extends to buffers. No doubt this extension
has been reasonable where the buffer is a primary data-structure for
Emacs the _text editor_. However, if there is to be a lexbind, does
this not imply a certain acknowledgement that Emacs is also a
_programming language_?

There is a tension here around buffer/text-editor vs. expressions/lisp

Indeed, I've been informed by at least one emacs-devel that,
 "Emacs is a _text editor_ not a programming language"

Is it not unreasonable to assume that some aspects of the buffers
priveleged status _must_ move over to make room for the lexbind?

IOW will any more "space" be affored Emacs lisp-lists or will the
buffer continue on as the primary "owner" of variable extent/scope?

--
/s_P\



reply via email to

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