unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Re: let vs. buffer local bindings
  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 19:15 ` Stefan Monnier
  2 siblings, 2 replies; 10+ messages in thread
From: Gareth Owen @ 2002-05-10 13:22 UTC (permalink / raw)
  Cc: Dave Pearson, Kim F. Storm

storm@cua.dk (Kim F. Storm) writes:

> Gareth Owen <usenet@gwowen.freeserve.co.uk> has found a peculiar
> interference between let and buffer local bindings.
> 
> Does anyone care to comment on the following result:

It should be noted that this seems only to be the case with 20.7.
Behaviour is more comprehensible in 21.1
-- 
Gareth Owen
"Computer games don't affect kids, I mean if Pac Man affected us as kids,
 we'd all be running around in darkened rooms, munching pills and listening
 to repetitive music."

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: let vs. buffer local bindings
  2002-05-10 14:21 let vs. buffer local bindings Kim F. Storm
  2002-05-10 13:22 ` Gareth Owen
@ 2002-05-10 13:32 ` Andreas Schwab
  2002-05-10 15:31   ` Kim F. Storm
  2002-05-10 19:15 ` Stefan Monnier
  2 siblings, 1 reply; 10+ messages in thread
From: Andreas Schwab @ 2002-05-10 13:32 UTC (permalink / raw)
  Cc: emacs-devel, Dave Pearson, Gareth Owen

storm@cua.dk (Kim F. Storm) writes:

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

*Note Introduction to Buffer-Local Variables: (elisp)Intro to
 Buffer-Local.

       *Warning:* When a variable has buffer-local values in one or more
    buffers, you can get Emacs very confused by binding the variable with
    `let', changing to a different current buffer in which a different
    binding is in effect, and then exiting the `let'.  This can scramble
    the values of the buffer-local and default bindings.

       To preserve your sanity, avoid using a variable in that way.  If you
    use `save-excursion' around each piece of code that changes to a
    different current buffer, you will not have this problem (*note
    Excursions::).

Andreas.

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE GmbH, Deutschherrnstr. 15-19, D-90429 Nürnberg
Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: let vs. buffer local bindings
  2002-05-10 13:22 ` Gareth Owen
@ 2002-05-10 13:48   ` Dave Pearson
  2002-05-10 14:53   ` Kim F. Storm
  1 sibling, 0 replies; 10+ messages in thread
From: Dave Pearson @ 2002-05-10 13:48 UTC (permalink / raw)
  Cc: emacs-devel, Kim F. Storm

* Gareth Owen <usenet@gwowen.freeserve.co.uk> [2002-05-10 14:22:31 +0100]:

> storm@cua.dk (Kim F. Storm) writes:
> 
> > Gareth Owen <usenet@gwowen.freeserve.co.uk> has found a peculiar
> > interference between let and buffer local bindings.
> > 
> > Does anyone care to comment on the following result:
> 
> It should be noted that this seems only to be the case with 20.7.
> Behaviour is more comprehensible in 21.1

The (0 1 3 4) result (which seems wrong) happens in 21.2.

-- 
Dave Pearson
http://www.davep.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* let vs. buffer local bindings
@ 2002-05-10 14:21 Kim F. Storm
  2002-05-10 13:22 ` Gareth Owen
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Kim F. Storm @ 2002-05-10 14:21 UTC (permalink / raw)
  Cc: Dave Pearson, Gareth Owen


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

Does anyone care to comment on the following result:

First try evalling:

(progn
  (make-variable-buffer-local 'foo)
  (setq-default foo 1)
  (list foo
	(let ((foo 2) (buf (generate-new-buffer "baz")))
	  (set-buffer buf) foo)
	(let ((foo 3) (buf (generate-new-buffer "baz")))
	  (set-buffer buf) foo)
	(let ((foo 4) (buf (generate-new-buffer "baz")))
	  (set-buffer buf) foo)))

which produces what seems to be correct:

  (1 2 3 4)


But now eval this:

(progn
  (setq foo 0)
  (list foo
	(let ((foo 2) (buf (generate-new-buffer "baz")))
	  (set-buffer buf) foo)
	(let ((foo 3) (buf (generate-new-buffer "baz")))
	  (set-buffer buf) foo)
	(let ((foo 4) (buf (generate-new-buffer "baz")))
	  (set-buffer buf) foo)))

which produces what seems to be wrong:

  (0 1 3 4)


-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: let vs. buffer local bindings
  2002-05-10 13:22 ` Gareth Owen
  2002-05-10 13:48   ` Dave Pearson
@ 2002-05-10 14:53   ` Kim F. Storm
  1 sibling, 0 replies; 10+ messages in thread
From: Kim F. Storm @ 2002-05-10 14:53 UTC (permalink / raw)
  Cc: emacs-devel, Dave Pearson

Gareth Owen <usenet@gwowen.freeserve.co.uk> writes:

> storm@cua.dk (Kim F. Storm) writes:
> 
> > Gareth Owen <usenet@gwowen.freeserve.co.uk> has found a peculiar
> > interference between let and buffer local bindings.
> > 
> > Does anyone care to comment on the following result:
> 
> It should be noted that this seems only to be the case with 20.7.
> Behaviour is more comprehensible in 21.1

My results are from the latest CVS emacs (aka 21.4), so there's still
something to explain :-)

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: let vs. buffer local bindings
  2002-05-10 13:32 ` Andreas Schwab
@ 2002-05-10 15:31   ` Kim F. Storm
  0 siblings, 0 replies; 10+ messages in thread
From: Kim F. Storm @ 2002-05-10 15:31 UTC (permalink / raw)
  Cc: emacs-devel, Dave Pearson, Gareth Owen

Andreas Schwab <schwab@suse.de> writes:

> storm@cua.dk (Kim F. Storm) writes:
> 
> |> Gareth Owen <usenet@gwowen.freeserve.co.uk> has found a peculiar
> |> interference between let and buffer local bindings.
> 
> *Note Introduction to Buffer-Local Variables: (elisp)Intro to
>  Buffer-Local.
> 
>        *Warning:* When a variable has buffer-local values in one or more
>     buffers, you can get Emacs very confused by binding the variable with
>     `let', changing to a different current buffer in which a different
>     binding is in effect, and then exiting the `let'.  This can scramble
>     the values of the buffer-local and default bindings.
> 
>        To preserve your sanity, avoid using a variable in that way.  If you
>     use `save-excursion' around each piece of code that changes to a
>     different current buffer, you will not have this problem (*note
>     Excursions::).
> 

I see.

But I had got the impression that the following changes to specbind
were supposed to remove that limitation.... I'm obviously mistaken:

2001-07-05  Gerd Moellmann  <gerd@gnu.org>

	* eval.c (specbind): Additionally record the buffer that was
	current when a buffer-local or frame-local variable was bound.

2001-07-03  Gerd Moellmann  <gerd@gnu.org>

	* eval.c (specbind): If SYMBOL has a frame-local binding, record
	the frame on the binding stack.  Change format of entries for
	local bindings on the binding stack to '(SYMBOL . WHERE)'.
	(unbind_to): Handle unbinding a frame-local variable.


-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: let vs. buffer local bindings
  2002-05-10 14:21 let vs. buffer local bindings Kim F. Storm
  2002-05-10 13:22 ` Gareth Owen
  2002-05-10 13:32 ` Andreas Schwab
@ 2002-05-10 19:15 ` Stefan Monnier
  2002-05-10 22:14   ` Kim F. Storm
  2 siblings, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2002-05-10 19:15 UTC (permalink / raw)
  Cc: emacs-devel, Dave Pearson, Gareth Owen

> 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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: let vs. buffer local bindings
  2002-05-10 19:15 ` Stefan Monnier
@ 2002-05-10 22:14   ` Kim F. Storm
  2002-05-12 16:34     ` Richard Stallman
  0 siblings, 1 reply; 10+ messages in thread
From: Kim F. Storm @ 2002-05-10 22:14 UTC (permalink / raw)
  Cc: emacs-devel, Dave Pearson, Gareth Owen

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:

> > 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.

Thanks Stefan.

I understand what's going on now.  

Considering that Gerd's fix has indeed improved emacs's behaviour in
this area, I think we need to change the elisp manual to reflect this.

Specifically, the following warning:

       *Warning:* When a variable has buffer-local values in one or more
    buffers, you can get Emacs very confused by binding the variable with
    `let', changing to a different current buffer in which a different
    binding is in effect, and then exiting the `let'.  This can scramble
    the values of the buffer-local and default bindings.

should be reworded into something less dramatic, e.g.

       *Warning:* When a variable has buffer-local values in one or
    more buffers, binding the variable with `let' and changing to a
    different current buffer in which a different binding is in
    effect, and then exiting the `let', the variable may not be
    restored to the value it had before the let.


Also, the example illustrating this is no longer valid, as the value of foo
is correct when we return to buffer "a", ie. the example should read:


     (setq foo 'b)
     (set-buffer "a")
     (make-local-variable 'foo)
     (setq foo 'a)
     (let ((foo 'temp))
        ;; foo => 'temp  ; let binding in buffer "a"
       (set-buffer "b")
        ;; foo => 'b  ; the global value since foo is not local in "b"
       BODY...)
     foo => 'b        ; we are still in buffer "b", but exiting the let
                      ; restored the local value in buffer "a"
     (set-buffer "a") ; which can be seen here:
     foo => 'a        ; we are back to the local value in buffer "a"

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: let vs. buffer local bindings
  2002-05-10 22:14   ` Kim F. Storm
@ 2002-05-12 16:34     ` Richard Stallman
  2002-05-13 20:07       ` Kim F. Storm
  0 siblings, 1 reply; 10+ messages in thread
From: Richard Stallman @ 2002-05-12 16:34 UTC (permalink / raw)
  Cc: monnier+gnu/emacs, emacs-devel, davep.news, usenet

Could you possibly edit the manual text?  It is in variables.texi.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: let vs. buffer local bindings
  2002-05-12 16:34     ` Richard Stallman
@ 2002-05-13 20:07       ` Kim F. Storm
  0 siblings, 0 replies; 10+ messages in thread
From: Kim F. Storm @ 2002-05-13 20:07 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

> Could you possibly edit the manual text?  It is in variables.texi.

Done.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2002-05-13 20:07 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
2002-05-10 22:14   ` Kim F. Storm
2002-05-12 16:34     ` Richard Stallman
2002-05-13 20:07       ` Kim F. Storm

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).