Finish up ep11
This commit is contained in:
parent
0a6628e7da
commit
a9d7962916
|
@ -598,7 +598,8 @@ CLOSED: [2022-09-11 Sun 11:08]
|
||||||
- https://lxsameer.com
|
- https://lxsameer.com
|
||||||
- [[https://twitter.com/lxsameer][@lxsameer]] on Twitter
|
- [[https://twitter.com/lxsameer][@lxsameer]] on Twitter
|
||||||
|
|
||||||
* Episode 10 - More on Macros
|
* DONE Episode 10 - More on Macros
|
||||||
|
CLOSED: [2022-11-04 Fri 15:25]
|
||||||
** Quasiquote aka backquote (`)
|
** Quasiquote aka backquote (`)
|
||||||
- Backquote constructs allow us to quote an expression, but selectively evaluate sub-expressions
|
- Backquote constructs allow us to quote an expression, but selectively evaluate sub-expressions
|
||||||
- Similar to a template engine for lisp expressions
|
- Similar to a template engine for lisp expressions
|
||||||
|
@ -628,3 +629,78 @@ CLOSED: [2022-09-11 Sun 11:08]
|
||||||
Let's discuss ~defflag~ and ~when-flag~ macros in [[file:../core/fg42/flags.el]]
|
Let's discuss ~defflag~ and ~when-flag~ macros in [[file:../core/fg42/flags.el]]
|
||||||
|
|
||||||
* Episode 11 - Common pitfalls of Macros
|
* Episode 11 - Common pitfalls of Macros
|
||||||
|
** Compiletime vs runtime
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
;; `do-something-with-side-effect' evaluates on compile time
|
||||||
|
;; in the macro's context
|
||||||
|
(defmacro wrong (x)
|
||||||
|
(when x
|
||||||
|
(do-something-with-side-effect x)))
|
||||||
|
|
||||||
|
;; `do-something-with-side-effect' evaluates on run time
|
||||||
|
;; in the caller's context
|
||||||
|
(defmacro correct (x)
|
||||||
|
(when x
|
||||||
|
`(do-something-with-side-effect ,x)))
|
||||||
|
#+END_SRC
|
||||||
|
** Variable Capture
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
;; `result' will hide any binding with the same name in the
|
||||||
|
;; parent scope
|
||||||
|
(defmacro wrong (f &rest body)
|
||||||
|
`(let ((result ,f))
|
||||||
|
(if result
|
||||||
|
,@body
|
||||||
|
(message "Failed: %s" result))))
|
||||||
|
|
||||||
|
(defvar result 1)
|
||||||
|
(wrong 200 (message "> %s" result))
|
||||||
|
|
||||||
|
;; Instead we need to generate a local binding
|
||||||
|
(defmacro correct (f &rest body)
|
||||||
|
(let ((var (gensym)))
|
||||||
|
`(let ((,var ,f))
|
||||||
|
(if ,var
|
||||||
|
,@body
|
||||||
|
(message "Failed: %s" ,var)))))
|
||||||
|
|
||||||
|
(defvar result 1)
|
||||||
|
(correct 200 (message "%s" result))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
More on *uninterned* symbols: https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html
|
||||||
|
|
||||||
|
** Many evaluation
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
;; The argument `x' will be evaluated 2 times in this example.
|
||||||
|
;; what if it contains side effects?
|
||||||
|
(defmacro wrong (x)
|
||||||
|
`(if ,x
|
||||||
|
(do-something-with ,x)
|
||||||
|
(do-somthing-else ,x)))
|
||||||
|
|
||||||
|
;; It's better to use a local binding for it and evaluate it
|
||||||
|
;; just once
|
||||||
|
(defmacro correct (x)
|
||||||
|
(let ((var (gensym)))
|
||||||
|
`(let ((,var ,x))
|
||||||
|
(if ,var
|
||||||
|
(do-something-with ,var)
|
||||||
|
(do-somthing-else ,var)))))
|
||||||
|
#+END_SRC
|
||||||
|
** Evaluating arguments of a macro
|
||||||
|
Never evaluate the arguments of a macro manually. E.g. with =eval=
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
;; `eval' here will be evaluated before the caller context
|
||||||
|
;; is even populated
|
||||||
|
(defmacro wrong (x)
|
||||||
|
(list 'setq (eval x) 'blah))
|
||||||
|
|
||||||
|
;; The correct way is to mark `x' for evaluation instead
|
||||||
|
(defmacro correct (x)
|
||||||
|
`(setq ,x 'blah))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
More info: https://www.gnu.org/software/emacs/manual/html_node/elisp/Eval-During-Expansion.html
|
||||||
|
** What's next?
|
||||||
|
|
Loading…
Reference in New Issue