unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: "Stefan Monnier" <monnier+gnu/emacs@RUM.cs.yale.edu>
Cc: emacs-devel@gnu.org, Dave Pearson <davep.news@davep.org>,
	Gareth Owen <usenet@gwowen.freeserve.co.uk>
Subject: Re: let vs. buffer local bindings
Date: Fri, 10 May 2002 15:15:28 -0400	[thread overview]
Message-ID: <200205101915.g4AJFSk21990@rum.cs.yale.edu> (raw)
In-Reply-To: 5xy9esxewc.fsf@kfs2.cua.dk

> Gareth Owen <usenet@gwowen.freeserve.co.uk> has found a peculiar
> interference between let and buffer local bindings.

Gerd has fixed one of the bad interactions between buffer-local and let-bound
variables, but we can't fix them all.  Or at least, I think that fixing
them such that there's a clear semantics will mean changing the current
semantics in a way that would break compatibility.

Currently, (let ((x val)) body) is similar to something like

   (push x)
   (unwind-protect
       (progn
         (setq x val)
         body)
     (setq x (pop)))

And similarly, `set-buffer' works by changing the "current"
value of all its local variables.  So in your example you get:

	(progn

`foo' is local in the buffer.  Its global value is 1.

	  (setq foo 0)

The local value is now 0.

	  (list foo

So you get 0 for the first elem of the list.

		(let ((foo 2) (buf (generate-new-buffer "baz")))

the current value of foo is now set to 2 (note that the current value
right now is the value in the local buffer).

		  (set-buffer buf) foo)

`foo' because foo is local in the current buffer but not in `baz',
its current value is changed to the one in `baz' which is the global value
(i.e. 1) so you get 1 as the second elem of the list.

At the end, the buffer-local value in the original buffer is reset
from 2 back to 0.  Before Gerd's fix (i.e. in Emacs<21) it would
have "reset" the current value instead, thus changing the global value
from 1 to 0.

		(let ((foo 3) (buf (generate-new-buffer "baz")))

Now the current value (i.e. the global value) is set to 3.

		  (set-buffer buf) foo)

When switching buffer, we're now sitching between two buffers where
foo is both times global, so foo's value is not changed.  We thus
get 3 and at the end, the global value is reset to 1.

		(let ((foo 4) (buf (generate-new-buffer "baz")))
		  (set-buffer buf) foo)))

I think by now you now how this works.  These semantics are pretty
ugly and basically "defined by the implementation" with a very
operational feeling to them.  Not declarative at all.  Another
problem with it is that it relies on assignments, which means that
it would interact very poorly with concurrency (while inside
(let ((newvar 1)) ...) another thread would see that the global value
of `newvar' is 1 instead of being unbound.

I think a good practice is to use with-current-buffer rather than set-buffer
because it avoids the most surprising cases (such as the one in your example).


	Stefan

  parent reply	other threads:[~2002-05-10 19:15 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-05-10 14:21 let vs. buffer local bindings Kim F. Storm
2002-05-10 13:22 ` Gareth Owen
2002-05-10 13:48   ` Dave Pearson
2002-05-10 14:53   ` Kim F. Storm
2002-05-10 13:32 ` Andreas Schwab
2002-05-10 15:31   ` Kim F. Storm
2002-05-10 19:15 ` Stefan Monnier [this message]
2002-05-10 22:14   ` Kim F. Storm
2002-05-12 16:34     ` Richard Stallman
2002-05-13 20:07       ` Kim F. Storm

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=200205101915.g4AJFSk21990@rum.cs.yale.edu \
    --to=monnier+gnu/emacs@rum.cs.yale.edu \
    --cc=davep.news@davep.org \
    --cc=emacs-devel@gnu.org \
    --cc=usenet@gwowen.freeserve.co.uk \
    /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).