emacs-devel
[Top][All Lists]
Advanced

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

Re: Can't M-x compile-defun `edebug' because dynamic variables are false


From: Stefan Monnier
Subject: Re: Can't M-x compile-defun `edebug' because dynamic variables are falsely taken as lexical.
Date: Thu, 13 Feb 2020 21:24:17 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

> Permanently is not the opposite of locally.  Instead
> of "permanently", shouldn't that text say "globally"?

Feel free to provide a patch that tries to clarify.  Part of the issue
is that (defvar VAR VAL) is just like (defvar VAR) when it's "processed"
by the byte-compiler: it won't affect bindings of VAR everywhere but
only within the corresponding lexical scope.  But when (defvar VAR VAL)
is *executed* then it subsequently will affect all interpreted code and
all the code that is subsequently compiled in that same Emacs session,
whereas *executing* (defvar VAR VAL) only affects the code subsequently
interpreted, and only within the current lexical scope.

> I think what you mean there is what Common Lisp calls
> "indefinite scope" - there are no limits on the scope
> of a special variable, i.e., _where_ it can be
> referenced.

That sounds about right, yes.

> ... the statement that "The variable is marked as 'special', meaning
> that it should _always_ be dynamically bound"

I'm not very happy with this statement, indeed: "always" isn't
quite right.

>>     if @var{value} is omitted then the variable is only
>>     marked special locally (i.e.@: within the current
>>     lexical scope, or file if at the top-level).
> This feature doesn't exist in Common Lisp, AFAIK.

AFAIK, in CL you can get something similar with (declare (special foo)).

> In CL, `defvar' always proclaims the variable special,
> whether or not an initial value is provided.

Indeed, Elisp is slightly different in this respect.

> And I think that for CL, a variable that is ever
> special is always and everywhere special, i.e., in
> all contexts.  It's always bound dynamically.

In Common Lisp

   (list
     (lambda (x)
       (let ((y x))
         (declare (special y))
         (lambda (z) (+ y z))))
     (lambda (x)
       (let ((y x))
         (lambda (z) (+ y z)))))

gives you two functions that don't behave the same because the `y`
binding in the first is dynamically scoped whereas that same `y` binding
is statically scoped in the second.

> When you say "Same for us", I'm guessing maybe you're interpreting
> what I wrote with "special" having your special ;-) interpretation as
> being context-dependent:

No, I'm saying that there's more to it than just either always or
never.  E.g. in Common Lisp after the system has *compiled* a chunk of
code with (defvar VAR ...), VAR may or may not be special (i.e. the
`defvar` must have affected the compiled code, but not necessarily the
state of the system that compiled the file).
[ In Elisp, the situation is somewhat similar, tho a bit
  less undefined.  ]

>> Does Common Lisp offer something like `special-variable-p`?
> Not that I know of.

Indeed.  And for good reasons: being a function it's hard to make it
provide the kind of semantic you expect from it, given the complexity
and scope-sensitivity of "specialness".

> But it also doesn't use `defvar' with and without second arg to
> declare specialness.

That's just a superficial syntactic difference.

Maybe the slightly deeper difference is that Common Lisp doesn't have
a way to say "all bindings of VAR under the current scope should be
dynamic", like (defvar VAR) does.  Instead it has (declare (special VAR))
which only talks about one particular binding.  But both Elisp's
`defvar` and CL's `declare` introduce the same issue that specialness is
not all-or-nothing and that a plain function like `special-variable-p`
can't give quite the answer we'd ideally want.


        Stefan




reply via email to

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