unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: MON KEY <monkey@sandpframing.com>
To: emacs-devel@gnu.org
Subject: `setplist' on local var escaping let binding
Date: Wed, 20 Oct 2010 19:28:17 -0400	[thread overview]
Message-ID: <AANLkTin4W1HkLQzfwk5jY1pC9=+-Mh+OoUcaBf7Z40EL@mail.gmail.com> (raw)

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	other threads:[~2010-10-20 23:28 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-10-20 23:28 MON KEY [this message]
2010-10-21  1:10 ` `setplist' on local var escaping let binding Stefan Monnier
2010-10-21  3:02   ` MON KEY
2010-10-21  4:26     ` Stephen J. Turnbull
2010-10-21  9:06     ` Andreas Schwab
2010-10-21 12:46     ` Davis Herring
2010-10-21 13:35     ` Thien-Thi Nguyen
2010-10-21 18:38     ` Stefan Monnier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='AANLkTin4W1HkLQzfwk5jY1pC9=+-Mh+OoUcaBf7Z40EL@mail.gmail.com' \
    --to=monkey@sandpframing.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).