Subject: bug#74145: 31.0.50; Default lexical-binding to t

From: Stefan Monnier <[email-masked]>
Date: Fri, 14 Feb 2025 11:53:34 -0500

> I believe the time has come to change the default dialect.
> I attached a suggested patch to do that.

OK, before we change the default, I propose the patch below, which
should not change the behavior at all, but allows users to

    (set-default-toplevel-value 'lexical-binding t)

IOW.  It does "everything" the previous patch did except actually change
the default.  The remaining step is to change the single line that sets
the default (currently to nil, then to t) and update the docs.

Any objection?

        Stefan
diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi
index b041678d8c8..1d60c6b0f88 100644
--- a/doc/lispintro/emacs-lisp-intro.texi
+++ b/doc/lispintro/emacs-lisp-intro.texi
@@ -3845,7 +3845,7 @@ Lexical vs Dynamic Binding Example
 If we use dynamic binding instead, the behavior is different:
 
 @example
-;;; -*- lexical-binding: nil -*-
+(defvar x) ;; Use dynamic binding for 'x'.
 
 (setq x 0)
 
@@ -3867,8 +3867,9 @@ Lexical vs Dynamic Binding Example
 @code{x}, since its binding is below the one from our @code{let}
 expression in the stack of bindings.
 
-(Some variables are also ``special'', and they are always dynamically
-bound even when @code{lexical-binding} is @code{t}.  @xref{defvar, ,
+(The @code{defvar} declaration above is said to make the variable
+``special'', which causes it to obey the dynamic binding rules instead of
+the default binding rules.  @xref{defvar, ,
 Initializing a Variable with @code{defvar}}.)
 
 @node if
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index e234db6fce5..15836591032 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -722,13 +722,6 @@ Edebug Eval
 pretty-printed in a separate buffer.
 @end table
 
-@cindex lexical binding (Edebug)
-  Edebug supports evaluation of expressions containing references to
-lexically bound symbols created by the following constructs in
-@file{cl.el}: @code{lexical-let}, @code{macrolet}, and
-@code{symbol-macrolet}.
-@c FIXME?  What about lexical-binding = t?
-
 @node Eval List
 @subsection Evaluation List Buffer
 
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index 89ccb8ea740..998a74d067a 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -285,7 +285,7 @@ Local Variables
 @defspec letrec (bindings@dots{}) forms@dots{}
 This special form is like @code{let*}, but all the variables are bound
 before any of the local values are computed.  The values are then
-assigned to the locally bound variables.  This is only useful when
+assigned to the locally bound variables.  This is useful only when
 lexical binding is in effect, and you want to create closures that
 refer to bindings that would otherwise not yet be in effect when using
 @code{let*}.
@@ -351,7 +351,7 @@ Local Variables
 done so that the value returned by the call is the value of @var{body}
 itself, as is the case in the recursive call to @code{sum} above.
 
-@code{named-let} can only be used when lexical-binding is enabled.
+@code{named-let} can be used only when lexical-binding is enabled.
 @xref{Lexical Binding}.
 @end defspec
 
@@ -392,7 +392,7 @@ Void Variables
 to evaluate the variable signals a @code{void-variable} error, instead
 of returning a value.
 
-  Under the optional lexical scoping rule, the value cell only holds
+  Under the optional lexical scoping rule, the value cell holds only
 the variable's global value---the value outside of any lexical binding
 construct.  When a variable is lexically bound, the local value is
 determined by the lexical environment; hence, variables can have local
@@ -710,8 +710,8 @@ Accessing Variables
   The usual way to reference a variable is to write the symbol which
 names it.  @xref{Symbol Forms}.
 
-  Occasionally, you may want to reference a variable which is only
-determined at run time.  In that case, you cannot specify the variable
+  Occasionally, you may want to reference a variable which is determined
+only at run time.  In that case, you cannot specify the variable
 name in the text of the program.  You can use the @code{symbol-value}
 function to extract the value.
 
@@ -1991,8 +1991,8 @@ File Local Variables
 
 @defvar permanently-enabled-local-variables
 Some local variable settings will, by default, be heeded even if
-@code{enable-local-variables} is @code{nil}.  By default, this is only
-the case for the @code{lexical-binding} local variable setting, but
+@code{enable-local-variables} is @code{nil}.  By default, this is the
+case only for the @code{lexical-binding} local variable setting, but
 this can be controlled by using this variable, which is a list of
 symbols.
 @end defvar
diff --git a/lisp/loadup.el b/lisp/loadup.el
index 98a47f2867f..ebd35291050 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -617,9 +617,9 @@ comp-subr-arities-h
           (unwind-protect
               (let ((tmp-dump-mode dump-mode)
                     (dump-mode nil)
-                    ;; Set `lexical-binding' to nil by default
+                    ;; Set `lexical-binding' to its default value
                     ;; in the dumped Emacs.
-                    (lexical-binding nil))
+                    (lexical-binding (default-toplevel-value 'lexical-binding)))
                 (if (member tmp-dump-mode '("pdump" "pbootstrap"))
                     (dump-emacs-portable (expand-file-name output invocation-directory))
                   (dump-emacs output (if (eq system-type 'ms-dos)
diff --git a/src/lread.c b/src/lread.c
index 46c705e5c76..df1caaf5732 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -1720,8 +1720,11 @@ DEFUN ("load", Fload, Sload, 1, 5, 0,
     }
   else
     {
-      if (lisp_file_lexical_cookie (Qget_file_char) == Cookie_Lex)
-        Fset (Qlexical_binding, Qt);
+      lexical_cookie_t lexc = lisp_file_lexical_cookie (Qget_file_char);
+      Fset (Qlexical_binding,
+	    (lexc == Cookie_Lex ? Qt
+	     : lexc == Cookie_Dyn ? Qnil
+	     : Fdefault_toplevel_value (Qlexical_binding)));
 
       if (! version || version >= 22)
         readevalloop (Qget_file_char, &input, hist_file_name,
@@ -2606,8 +2609,11 @@ DEFUN ("eval-buffer", Feval_buffer, Seval_buffer, 0, 5, "",
   specbind (Qstandard_output, tem);
   record_unwind_protect_excursion ();
   BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
+  lexical_cookie_t lexc = lisp_file_lexical_cookie (buf);
   specbind (Qlexical_binding,
-	    lisp_file_lexical_cookie (buf) == Cookie_Lex ? Qt : Qnil);
+	    lexc == Cookie_Lex ? Qt
+	    : lexc == Cookie_Dyn ? Qnil
+	    : Fdefault_toplevel_value (Qlexical_binding));
   BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
   readevalloop (buf, 0, filename,
 		!NILP (printflag), unibyte, Qnil, Qnil, Qnil);