reddit / emacs

Question about setq, nil, and -1

teckau22 · 2022-11-21 12:39
So I've been going through my `init.el` config, trying to make sense of some things, and I've noticed the following: 1. Some variables are set using `setq` (example: `(setq mouse-wheel-progressive-speed nil)`). 2. Some variables are set without using `setq` (example: `(tool-bar-mode -1)`). 3. Some variables are set to `nil` by setting them to `nil` (see point 1) while some variables are set to `nil` by setting them to `-1` (see point 2). According to the [docs](https://www.gnu.org/software/emacs/manual/html_node/eintr/Truth-_0026-Falsehood.html), `nil` is false, and everything else is true. So my questions are: 1. Why does `(tool-bar-mode -1)` set the variable to `nil`? 2. Why are some variables set using `setq` and some without? 3. What is the difference between `(setq some-variable -1)`, `(some-variable -1)`, `(setq some-variable nil)`, and `(some-variable nil)`? Are these equivalent? If yes, what would be the best practice?
sledgespread · 2022-11-21 12:59
`tool-bar-mode` is a function as well as a variable, so `(tool-bar-mode -1)` calls the function `tool-bar-mode` with `-1` as the argument. `-1` isn't equivalent to `nil`, it's a special argument to mode functions which turns off the mode. I think the use of `-1` is a workaround for the lack of default arguments and the fact that Emacs lisp doesn't have a `false` (only `nil`). Imagine this: you want to have a `tool-bar-mode` function with one argument, if the argument is truthy then the mode is enabled, otherwise it's disabled. But also you want to be able to call it with no arguments to enable the mode (to make it easier to use in hooks). Since `nil` is the value passed for a missing argument `(tool-bar-mode nil)` has to *enable* the mode. So you need some other argument value to disable it, someone picked `-1` for this. (I think we have proper default arguments now, but it's much too late to change these interfaces.)
yashasolutions · 2022-11-21 13:04
`(tool-bar-mode -1)` seems like a function with an argument more than setting a variable (which it might do internally) `nil` or `-1` seems more like a question of what the code actually expect Try `M-X describe-variable` or `describe-function` should give you the expected params
teckau22 · 2022-11-21 13:45
Thank you, this makes a lot of sense. Looking at the help page of both `tool-bar-mode` (the variable) and `tool-bar-mode` (the command), if I understand correctly, the variable `tool-bar-mode` indicates what the status of the `tool-bar-mode` mode is (if it is enabled or disabled). So setting the variable `tool-bar-mode` to `nil` (example: `(setq tool-bar-mode nil)`) does not actually do anything, since that variable simply holds the enabled/disabled state of the actual mode. To disable the mode, one has to go through the function (`(tool-bar-mode -1)`). Is this correct?
Illiamen · 2022-11-21 14:05
Yes, that's correct. A special case is when customizing user options in the Customization menu. In that menu, it makes it seem like you are setting the value of the mode's variable, but it is actually calling the mode's function with the correct argument.
teckau22 · 2022-11-21 14:19
All my questions have been answered, thank you all very much.
[deleted] · 2022-11-21 14:47
[deleted]
arthurno1 · 2022-11-21 14:55
If you press C-h f tool-bar-mode RETURN and Emacs will display the documentation for the function: ( ... ) This is a global minor mode. If called interactively, toggle the ‘Tool-Bar mode’ mode. If the prefix argument is positive, enable the mode, and if it is zero or negative, disable the mode. If called from Lisp, toggle the mode if ARG is ‘toggle’. Enable the mode if ARG is nil, omitted, or is a positive number. Disable the mode if ARG is a negative number. ( ... ) Also, when you call (tool-bar-mode -1), you are calling a function that will do something based on the argument, and as the docs says, if the argument is a negative number it will disable the mode, with other words, you are not setting the variable to nil. However, there is a variable with the same name that will get set to nil by that function :). Emacs is so called [Lisp-2](https://en.wikipedia.org/wiki/Common_Lisp#The_function_namespace), which means you can have a function and variable with the same name. When we [define a minor mode](https://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-Minor-Modes.html) Emacs automatically creates a variable and a function with the same name, to toggle a mode on and off That is what you are experiencing there. You can check docs for variables by typing C-h v variable-name RETURN and observer that th doc for tool-bar-mode *variable* tells that setting this variable to nil manually (via setq) does nothing. That is expected since it is designed for use with the toggle function for the mode in this case. I suggest taking a tutorial on lisp, preferably Emacs lisp, but any lisp can do :). You can learn Emacs Lisp with the included *An Introduction to Programming in Emacs Lisp* book in your Emacs. If you type C-h i for the info manual, choose Emacs Lisp Intro from the menu, and read it directly in your Emacs; or if you prefer [from the web](https://www.gnu.org/software/emacs/manual/eintr.html). If you want something shorter, try this: https://learnxinyminutes.com/docs/elisp/ https://github.com/chrisdone/elisp-guide https://bzg.fr/en/learn-emacs-lisp-in-15-minutes/ https://www.emacswiki.org/emacs/LearnEmacsLisp
timmymayes · 2022-11-21 15:47
I'm currently learning elisp via introduction to elisp and it's been very useful for decoding my config . You can read it inside emacs and evaluate the problems in the scratch buffer.
flyin1501 · 2022-11-21 19:39
`(abc nil)` is a function call, not setting a variable. You have confused minor mode functions with their similarly named variable counterparts. Minor modes are functions that toggle a boolean variable then runs some code afterwards*. Often, the variable has the same name as the function. Almost always the "some code" enables some behavior when the variable is toggled to true, and reverts those changes when it's toggled to false. *plus some other effects like enabling a local keymap while it's active. See the manual for and the source code for `define-minor-mode` for an actual definition Minor modes almost always have this text in their help string: > If called from Lisp, toggle the mode if ARG is toggle. Enable the mode if ARG is nil, omitted, or is a positive number. Disable the mode if ARG is a negative number. `(some-minor-mode -1)` thus sets its corresponding variable to nil, then runs some code that (depending on how the minor mode is implemented) reflects that. `setq` is the simplest form of setting the value of a variable. If you setq a minor mode variable, you will not run the minor mode body, which is almost always going to result in unexpected behavior. Read the docstring (with `describe-variable` for variables and `describe-function` for functions, macros (like `defun` or `define-minor-mode`), or special forms (like `if`)) to figure out what something is. --- A variable has a name and a value. In Emacs Lisp (like in Common Lisp) a variable has *two* value fields: one referred to as the value, the other the "function value". This is why (setq abadvariablename (lambda () "hello")) (abadvariablename) will error out. This allows (defun my/example (list) (list list)) to work: the `list` variable does not shadow the `list` function. (To call a function value, and thus a variable holding a function value in its "value" cell, use `funcall`.) (The "value" field is only used when referencing variables for dynamic / special variables. Normal variables (lexical variables) store their value in their lexical scope, such as the surrounding function or `let`. The function field is, nevertheless, global.)
11fdriver · 2022-11-21 21:33
AFAIK there is still not really a proper default argument in Emacs Lisp. I don't think that should change at this point, but it's why you still see let-forms that rebind `&optional` arguments, or the good ol' `(unless arg (setq arg 1))`. What you can do is use `cl-defun`, which allows the common-lisp syntax `&optional (x 4)` as well as some other neat tricks like argument destructuring. Perhaps surprisingly, `cl-defun` is just a macro (albeit a thick one) wrapping regular `defun`.
raevnos · 2022-11-22 08:58
>Perhaps surprisingly, cl-defun is just a macro (albeit a thick one) wrapping regular defun. Why is that surprising? It's lisp after all.
11fdriver · 2022-11-22 09:08
I meant that perhaps it's surprising that you don't need to replace the `defun` internals outright to handle true-optional arguments, just a little bit of preprocessing of the arguments. I'm not overly surprised personally, but I thought I'd mention it for those interested. :)
sledgespread · 2022-11-22 13:26
Yeah I think `cl-defun` is the "proper default args" thing that I remembered.