22

I'm not quite clear on all the variations of buffer-local variables, even after reading all the doc and a bunch of postings here on SX.

Here's a summary of my understandings:

(defvar foo ..) declares a dynamic variable for the file. But the variable is (1) not known to other files unless they include a defvar statement as well, and (2) the variable is global in scope, not buffer local.

(make-variable-buffer-local foo) after the defvar above tells the compiler and everyone else that the variable foo is to be treated as buffer-local everywhere it is set, when it is set. So this pattern is good style for declaring a buffer-local variable, putting both statements back-to-back in the file.

(defvar xxx ...)                    ;declare xxx with global scope
(make-variable-buffer-local 'xxx)   ;but now make it buffer-local everywhere

For convenience, the (defvar-local xxx ...) form can be used as one line, in place of the two lines above:

(defvar-local xxx ...)       ;make xxx buffer local everywhere

Once declared as above, the variable xxx can be used like any other variable in setq statements.

If I just want to have a single instance of a buffer-local variable that is already a global dynamic variable, I would use the following declarations. The first one declares the global-scope dynamic variable, and the second statement makes just one instance of a buffer-local version of that variable, in the current buffer:

(defvar xxx ...)             ;declare xxx with global scope
(make-local-variable 'xxx)   ;make xxx local in this buffer only

Now for my explict questions (all the above were implicit questions on whether my understanding is correct).

When setting the value of variables, I can use setq or setq-local. When should setq-local be used? Why?

What happens if I use setq-local on buffer-local vars, or non-buffer-local vars?

Is setq-local required for a defvar-local declared variable?

Will setq-local on a normal defvar declared variable turn it into a buffer-local variable? (In other words, is setq-local somehow the equivalent of a (make-variable-local xxx) declaration?

Scott Weldon
  • 2,695
  • 1
  • 17
  • 31
Kevin
  • 1,308
  • 8
  • 20
  • Thanks for the extra labor Scott. I will put in the extra backquotes from here on in. – Kevin Jul 30 '16 at 01:39
  • 2
    `(setq-local VAR VALUE)` is just shorthand for `(set (make-local-variable VAR) VALUE)`, which was (and still is) a common idiom. – Drew Jul 30 '16 at 06:33

1 Answers1

25

Most of your assumptions are close. I'll mention a few later. But, first the main question.

The form setq-local is merely a convenience, it is the same as doing make-local-variable followed by setq. If you had done a C-h f setq-local to see the documentation and clicked through to the source you might have seen this. That's how I verified my first impression. The code is a little obscure, though, since it is optimizing on things like the fact that make-local-variable actually returns the variable itself. Using setq-local is a way to point out the localness in some code, so that others know the code can't be playing with the global value of the variable. You do not need to use it to access local variables. Any variable can be made buffer-local and that will affect all code that touches the variable (except if it goes out of its way to get the global copy with setq-default or similar).

That's the primary answer. Now, there are a few things in your background that are a little off. Since you asked about that, I'll address some things.

The first is "not known to other files". This isn't really true. Any code can reference any global variable (that's why they are called "global") without including the defvar (and C-h f defvar says so). In fact, there should only be one main defvar (with docstring and default value) for each global variable. A defvar with just the variable name can be used to suppress a byte-compiler warning. Emacs only uses the value from the first one it sees¹ and the docstring from the last one. If there are multiple defvars with value/docstring they can be confusing to people reading the code. And the order of loading files will matter.

Some variables are intended to be used only as buffer-local and those are the ones that use defvar-local (or the two part defvar / make-variable-buffer-local which it is short for, mostly in older code before the short form was added). This makes it be buffer-local in all buffers. For some variables, their primary use is not buffer-local, but for some reason you may want one buffer to have a different value. That's when you use make-local-variable, usually in some buffer setup code almost never right after a defvar.

And as a general thing, there are two purposes to the defvar forms. One is to have some documentation, so that C-h v can be used by others to know what the variable is for. The second is to declare a "default" value, so that the variable is always set. The declaration of the default value only affects the global (or default) instance of a variable, and is only used if that instance is not already set to something. That means that if you setq some variable and then include the file with the defvar (e.g. through a require), the defvar will not change the value.

¹ More precisely, defvar doesn't modify the value of the variable if it's already set (it does set the docstring however); this is meant so that the user's init file can do (setq some-variable) before a package is loaded to override the package's default value.

MAP
  • 582
  • 4
  • 11
  • 1
    Thanks for the very clear answer, it helps a lot. When I used the phrase "not known to other files" I was thinking of free variable warnings because those other files will think the variable is free unless I add a defvar to them too. I like your statement that `set-local` tells readers that a local var is being set. Anything I can do to improve readability of my code is good! PS. I will try to click through to the source more often; at my current level of development, it often doesn't really get at the semantics... :-) – Kevin Jul 30 '16 at 00:59
  • 1
    "there should only be one `defvar` for each global variable" isn't strictly correct -- there are situations when `(defvar VARNAME)` *without* a value should be declared, independently of the proper definition (with initial value and ideally a docstring) of that VARNAME. – phils Jul 30 '16 at 13:46
  • 2
    Note also that `setq-local` and `defvar-local` were only introduced in Emacs 24.3. – phils Jul 30 '16 at 13:48
  • 1
    @phils, could you please identify the situations that you speak of, where `(defvar varname)` should be declared _without_ a value? I'm thinking that's what Drew suggested in another thread when I was asking how to get rid of free variable warnings in my files for globals I had declared elsewhere. I do that now. Is that the situation that you speak of? – Kevin Jul 30 '16 at 14:53
  • 1
    Avoiding byte-compilation warnings is one reason, yes (see `C-h i g (elisp) Warning Tips`). The other is for libraries using lexical-binding, to ensure (if necessary) that a variable is dynamically bound rather than lexically bound. – phils Jul 30 '16 at 15:35
  • @phils is right. That's a use for `defvar` with only the variable, one that I'd forgotten (because the other LISP I use has a different name for that case). I think I'll edit it into my answer... – MAP Jul 30 '16 at 15:41
  • Isnt it set after make-local eg (set (make-local-variable 'tab-width) 8) – RichieHH Apr 03 '21 at 10:25