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

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

RE: [External] : Re: Lexical vs. dynamic: small examples?


From: Drew Adams
Subject: RE: [External] : Re: Lexical vs. dynamic: small examples?
Date: Sun, 15 Aug 2021 00:29:50 +0000

> Now if you M-x trim-whitespaces-at-eol in a read-only buffer, you'll get a
> "Buffer is read-only" error.  Suppose you want to make that function work
> for read-only buffers.  If Emacs Lisp only had lexical binding, you would
> have to alter the global "buffer-read-only" variable, that is, to do
> something like:
> 
> (defvar saved-buffer-read-only)
> (defun delete-whitespace-at-eol ()
>    (interactive)
>    (setq saved-buffer-read-only buffer-read-only)
>    (setq buffer-read-only nil)
>    ...
>    (setq buffer-read-only saved-buffer-read-only))

`buffer-read-only' is a dynamically scoped, set, and
bound variable.  (It's also buffer-local.)  What you did
there was change the value for the dynamic extent of
the function call.  It's not defined by the scope of the
function definition.

All variables defined using defvar and defcustom are
dynamically scoped.  Same with top-level `setq', i.e.,
variables that are not explicitly defined in any
scope, other that the top level.

Same with frame parameters, faces, etc. - all essentially
dynamically-scoped variables.  Their values have
indefinite scope and dynamic extent.

"Dynamic scope" is a misnomer, BTW; it means only that -
no particular scope and dynamic extent.  See the very
good explanation in CLTL:

https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node43.html#SECTION00700000000000000000

Common Lisp calls such variables "special" variables.

Wrt usefulness: if you've ever used user options or
defvar variables, or frame parameters, or faces,...
then you recognize their utility.  Now try to imagine
Emacs, as a flexible, dynamic user-interaction
environment/lab _without_ dynamic binding...

> This becomes much simpler with dynamic binding:
> (defun delete-whitespace-at-eol ()
>    (interactive)
>    (let ((buffer-read-only nil))
>      ...))

That's just a simpler way to do the same thing.
In both cases, it is the globally visible
(buffer-local) variable whose value is changed
for the _duration_ of the function call (unless
something else changes it in the meantime).

`let' binds the global variable (which, again,
happens to be buffer-local).  That's how `let'
behaves with a "special" var.  Otherwise, i.e.,
for vars that are not "special", `let' provides
a lexical binding - the scope ends where the
`let' ends, lexically.

Dynamic scope/binding means variable name capture
is always an inherent, potential problem.

>From the CLTL chapter on Scope and Extent cited
above, remember this:

"A reference by name to an entity with dynamic extent
 will always refer to the entity of that name that
 has been most recently established that has not yet
 been disestablished."



reply via email to

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