Emacs Lisp For Hackers: All Things Variables
All Things Variables
Time to get into Variables.
If you are used to most programming languages, setting and updating
variables is the way you operate. There are a few ways this happens in
Emacs Lisp, but the most fundamental way is via setq
.
The special form setq
is extremely simple. It sets the value of a
symbol, which can be referenced later:
ELISP> (setq x 10)
10
ELISP> (+ x x)
20
There is another, similar function: defvar
.
The special form defvar
is similar in spirit to setq.
It allows you to define special variables, give them default values if
they do not already have values, and provide documentation for what
that variable “means”. Some examples:
(defvar user-name "Joel"
"The name of the person currently using Emacs.")
(defvar pomodoro-done-hook nil
"Hook that gets done whenever a pomodoro is finished.")
(defvar my-favorite-numbers '(4 8 15 16 23 42))
Use defvar
whenever you want to “declare” a variable to have some
special, global meaning.
Emacs Lisp is not the most opinionated of Lisps, so it lets you do all
the imperative programming that you want. However, a cleaner style of
handling variables is let
:
ELISP> (let ((x 10))
(+ x x))
20
Let takes a list of symbol and value bindings, and then evaluates
body, which represents the remaining arguments to let
.
Another slightly more difficult example should help clarify the concept
ELISP> (let ((x 10))
(list (let ((x "hi"))
x)
x))
("hi" 10)
This example illustrates how let
changes bindings. There are two
let
calls in this fragment. The outer call sets the value of the
symbol x
to 10. After this happens, the body call occurs. Within the
call to list
is a second let
form. This let
binds “hi” to the
symbol x
, which is then returned from the let
. This value (“hi”)
then gets made into a list, along with the original value of x, which
was 10. Both of these then get returned, which gives us ("hi" 10")
.
The bindings list for let
can take multiple bindings, which will all
then be available when the body is executed:
ELISP> (let ((a "Heya")
(b "worldz"))
(concat a " " b))
"Heya worldz"
There is another form of let
, called let*
, which makes each
binding available to
the next binding when it is evaluated. This is actually extremely
useful, but when I first encountered this idea the usefulness was not
immediately apparent. So, lets have one final example, shall we?
Lets look at a quick regular expression example:
ELISP> (let* ((filename "2012-09-10-a-blog-post.markdown")
(file-without-extension-rx "\\(.*\\).markdown")
(regular-filename (progn
(string-match file-without-extension-rx filename)
(match-string 1 filename))))
(message "The filename sans extension was: %s" regular-filename))
"The filename sans extension was: 2012-09-10-a-blog-post"
Notice how the regular-filename
value comes from a compound
expression, and that the arguments two both function calls come from
the previous bindings. This is really, really useful in practice.
Well, that’s about it for the basics of Emacs Lisp. With the Info documentation and the documentation for the various parts of Emacs, you should be equipped to hack the good hacks.
Of course, I’m not done helping you learn Emacs Lisp. There are many areas of the Emacs APIs that can use some simplification. And then, there is the reorganization thing that will happen when this series gets rolled into book form. So, stay tuned.