From a9d79629161409e972261540ddb2f875defc6e9b Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Sat, 5 Nov 2022 12:46:53 +0000 Subject: [PATCH] Finish up ep11 --- docs/videos.org | 78 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/docs/videos.org b/docs/videos.org index dbf2b65..d0bc837 100644 --- a/docs/videos.org +++ b/docs/videos.org @@ -598,7 +598,8 @@ CLOSED: [2022-09-11 Sun 11:08] - https://lxsameer.com - [[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 (`) - Backquote constructs allow us to quote an expression, but selectively evaluate sub-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]] * 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?