Learning Elisp 02 Variable and Scope
Variables
- Set vairbales and Define vairables are different
- Define Buffer-local variables
- Understanding variable scopes
- Creating Variable scope with
let
- Defining and setting customization variables
Variable is a symbol that binds with a value : 'tab-width
-> 4
Set variables
Variables are symbols binds to values, what setq
means is “set
quote”, a convient way to write
1
2(set 'tab-width 4)
3
4;; The variable doesn't have to exist or be pre-defined
5
6(set 'i-dont-exist 5)
Documenting Variables
defvar
allows one to assign documentations to the created variables
Remark:
- defvar will can be assigned to variables that doesn’t exist yet
- if the variable has already created and has been assigned with a
default value, the assigned defult value from the
defvar
function won’t work (don’t seem to apply in my case…)
1
2(defvar i-dont-exist 100
3"This is a variable to test whether the default value is the existing
4one or the newly assigned one")
Set buffer-local value for variables
1
2(setq some-value 2)
3
4(setq-local some-value 5)
5
6;; after using setq-local, the setq will only set the buffer-local binding
7(setq some-value 4)
Making a variable local for all buffers
1
2(setq not-local-yet t)
3(make-variable-buffer-local 'not-local-yet)
Setting default values
1(setq-default not-local-yet nil)
Scope
Define a local scope using let
, the region inside that let
is
another scope.
Define a locals cope with let
If defining a loop and set the variable in global scope, the function
will only be able to run once:
1
2(setq x 0)
3
4(defun do-the-loop ()
5 (message "Starting the loop at %d" x)
6 (while (< x 5)
7 (message "Loop index is %d" x)
8 (cl-incf x)) ;; (equivalent to (setq x (1+ x))
9 (message "DONE!"))
10
11(do-the-loop)
To avoid the problem:
1
2(defun do-the-loop ()
3 (let ((x 0))
4 (message "Starting the loop at %d" x)
5 (while (< x 5)
6(message "Loops index: %d" x)
7(cl-incf x))
8 (message "DONE Looping!")))
9
10(do-the-loop)
- Why
(())
? Becauselet
is a list, and the argument pass onto thelist
is also alist
of (sort of) key-value pair.
1
2(let ((x 5)
3 (y 7))
4 (* x y))
- What if you want to refer to
y
in another variable, sayz
?(let ((x 10) (z (+ y 5))) (* x y))
will throw error message:symbol y is void
- The right solution is to use
let*
instead
1
2(let* ((y 5)
3 (z (+ y 5)))
4 (* y z))
let*
is in essence a nestedlet
1
2(let ((y 5)) (let ((z (+ y 5))) (* z y)))
Dynamic scope
- The value associated with a variable might change depending on where an expression gets evaluated
- If the function is executed in a local scope predicated by
let
, the variable will be evaluated based on the value inside the scope oflet
1
2(setq x 5)
3
4(defun do-math (y)
5 (+ x y))
6
7(do-math 10) ;;15
8
9(let ((x 100)) (do-math 10)) ;; 110
Defining customization variables
Customizable variables is user-facing setting so people can set up those variables without coding.
Using defcustom
Set customizable variable (correctly)
The variables defined to be customized and setq
might not trigger the
behavior! The correct way to set those customized variable is to use
cutomize-set-variable
1
2(customize-set-variable 'tab-width 2)
3(customize-set-variable 'org-directory "~/Notes")
If using use-package
, use :custom
section
1
2(use-package emacs
3 :custom
4 (tab-width 2))
Use C-h v
- describe varibale to check whether a variable is
customizable or not; Another way is to use custom-variable-p
to
evaluate on the variable symbol.
1
2(custom-variable-p 'tab-width)