[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Why is Elisp's defvar weird? And is eval_sub broken?
From: |
Kelly Dean |
Subject: |
Re: Why is Elisp's defvar weird? And is eval_sub broken? |
Date: |
Sat, 14 Feb 2015 07:35:58 +0000 |
Stefan Monnier wrote:
> The declaration of the var as being dynamically-scoped (aka "special")
> is *local* to the (rest of the) current scope (typically the current file).
>
> This is indispensable so that one package can use a dynamically-bound
> variable `foo' without breaking some other package that expects `foo' to
> be lexically-bound.
desktop.el doesn't use desktop-first-buffer, desktop-buffer-ok-count, and
desktop-buffer-fail-count as global variables. It only uses them as dynamic
variables, for implicit arguments and return values of functions. I.e. outside
of a let-binding, it doesn't use the symbols (except in defvar, just to avoid
byte compiler warnings).
For that case, what I had in mind was a dynamic-let special form, being the
same as «let», except with the following case removed:
if (!NILP (lexenv) && SYMBOLP (var)
&& !XSYMBOL (var)->declared_special
&& NILP (Fmemq (var, Vinternal_interpreter_environment)))
lexenv = Fcons (Fcons (var, tem), lexenv);
so it always just does specbind (var, tem). The byte compiler could flag an
error if you use dynamic-let on a symbol that's already used as a lexical
variable. This way, there's no need to use defvar on symbols such as the
desktop.el symbols above. So defvar can be reserved just for the symbols that
really are special, i.e. the ones that are used as global variables and for
which dynamic variables instead of lexical variables are created to shadow the
globals when you let-bind the symbols using standard «let» (in any file).
A declaration of free dynamic variables for a function could tell the byte
compiler that those free variables aren't typos, since otherwise the byte
compiler would expect either the symbol to be declared special or a lexical
variable by that name to be in scope.
Also have a lexical-let special form (replacing the old lexical-let macro),
being the same as «let», except with case above replaced by:
CHECK_SYMBOL (var);
if (NILP (lexenv)) lexenv = Qt;
lexenv = Fcons (Fcons (var, tem), lexenv);
and have it never do specbind (var, tem). The byte compiler could give a
warning if you use lexical-let on a symbol that's declared special. Then
everybody could use this faster form in the cases where all the variables being
bound in the «let» are supposed to be lexical. This also has the advantage of
ensuring that those variables _are_ bound lexically even if you forgot that
some of the symbols you're using were declared special, and the byte compiler
can see your intent to use lexicals and warn you about the specials, which
helps catch bugs.
Then you never need standard (and slow, and bug-prone) «let», except for
compatibility with old code, and for the rare cases where you might need it for
some mind-bending macros.
I would vote for ⌜dlet⌝ and ⌜llet⌝ as the names, or at least ⌜dynlet⌝ and
⌜lexlet⌝, since Elisp code is already too verbose.
For both correctness and speed, have the standard llet (accessible to
interpreted code) include the CHECK_SYMBOL (var) above, and have the standard
dlet include a runtime check of shadowing a lexical. Have byte-compiled code
use a pair of optimized special forms, not accessible to interpreted code, with
those checks omitted, since they're done at compile time.
> Normally, such conflicts should never happen
> because all special vars should be named with a "package prefix", but
> sadly, reality is different, so it was indispensable to make this
> effect local, to allow lexical-binding code to work reliably.
By using llet, the byte compiler will catch such conflicts, and your code
(interpreted or compiled) that uses it will work reliably despite the
conflicts. This means defvar's weird behavior is no longer needed.
- Why is Elisp's defvar weird? And is eval_sub broken?, Kelly Dean, 2015/02/12
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Stefan Monnier, 2015/02/13
- Re: Why is Elisp's defvar weird? And is eval_sub broken?,
Kelly Dean <=
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Stefan Monnier, 2015/02/14
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Daniel Colascione, 2015/02/15
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Kelly Dean, 2015/02/16
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Stefan Monnier, 2015/02/16
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Kelly Dean, 2015/02/17
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Stefan Monnier, 2015/02/18
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Kelly Dean, 2015/02/19
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Stefan Monnier, 2015/02/19
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Kelly Dean, 2015/02/19
- Re: Why is Elisp's defvar weird? And is eval_sub broken?, Stefan Monnier, 2015/02/19