emacs-devel
[Top][All Lists]
Advanced

[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: Stefan Monnier
Subject: Re: Why is Elisp's defvar weird? And is eval_sub broken?
Date: Fri, 13 Feb 2015 14:03:53 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

> But that's wrong. If INITVALUE is missing, and lexical-binding is
>  t (as is the case in desktop.el), then not only is the value not set,
>  but also the variable is _not_ declared special, even if the defvar
>  is at top level.

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

> That means that even after loading desktop.el, if you let-bind the
> three variables above in a function defined in a file other than
> desktop.el, and lexical-binding is t in that other file, then those
> variables will be bound lexically, not dynamically.

That's right.
If you're lucky (more specifically, if you only let-bind those vars but
you don't use them locally), the byte-compiler will emit a warning that
those let-bindings aren't used (which is usually a sign that you need
to add a (defvar <foo>) earlier in the file).

> That's because eval_sub in eval.c looks up the variable in the lexical
> environment using only Fassq, without first using Fmemq to check for
> a local dynamic binding.  Is that behavior actually correct?

I wouldn't argue it's correct, but I'd rather not pay the price of an
additional memq check to cater to such brain-dead misuse of defvar.
Arguably, the byte-compiler should flag such misuse, tho currently it
misses it (tho it does catch the case of:

   (let ((my-foo 0))
     (let ((my-foo 1))
       my-foo))
   
   (defvar my-foo)


-- Stefan



reply via email to

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