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

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

Re: Lexical vs. dynamic: small examples?


From: Gregory Heytings
Subject: Re: Lexical vs. dynamic: small examples?
Date: Sat, 14 Aug 2021 19:00:29 +0000



I am trying to write a section on lexical vs. dynamic binding for a tutorial on Emacs Lisp, and I am looking for very short demos that show how things work differently in dynamic and in lexical binding...


Suppose you write a function to remove unnecessary whitespaces at the end of lines:

(defun delete-whitespace-at-eol ()
  (interactive)
  (save-excursion (replace-regexp " *$" "" nil (point-min) (point-max))))

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)
  (save-excursion (replace-regexp " *$" "" nil (point-min) (point-max)))
  (setq buffer-read-only saved-buffer-read-only))

This becomes much simpler with dynamic binding:

(defun delete-whitespace-at-eol ()
  (interactive)
  (let ((buffer-read-only nil))
    (save-excursion (replace-regexp " *$" "" nil (point-min) (point-max)))))

The "let ((buffer-read-only nil))" creates a new "buffer-read-only" variable and sets it to nil. When "replace-regexp", and the functions called by "replace-regexp", consult the value of the "buffer-read-only" variable, they will see the "buffer-read-only" variable created in "delete-whitespace-at-eol", and its value "nil", instead of the global "buffer-read-only" variable.

It is easier to think that "let ((buffer-read-only nil))" creates a new "buffer-read-only" variable, but technically this is not correct. What happens instead is that the old value of "buffer-read-only" is saved, the value of "buffer-read-only" is updated, and upon returning from the "let", the saved value is restored.



reply via email to

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