[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] fix/bug-31311-pcase-doc 977bd10 3/3: expand @item "Side-ef
From: |
Thien-Thi Nguyen |
Subject: |
[Emacs-diffs] fix/bug-31311-pcase-doc 977bd10 3/3: expand @item "Side-effecting code..." |
Date: |
Tue, 15 May 2018 10:31:42 -0400 (EDT) |
branch: fix/bug-31311-pcase-doc
commit 977bd10f5e70c18019326f6df65e1de8c1ab26b0
Author: Thien-Thi Nguyen <address@hidden>
Commit: Thien-Thi Nguyen <address@hidden>
expand @item "Side-effecting code..."
- add example square-double-digit-p/{OK,WRONG}
- list all places where evaluation occurs (i.e., all places
in which it's ill-advised to use side-effecting references,
i.e., EVERYWHERE :-D)
---
doc/lispref/control.texi | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index 9044a2b..2e03ae0 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -635,6 +635,71 @@ On the other hand, B uses two separate symbols, @code{s1}
and
@item Side-effecting code referencing @var{symbol} is undefined.
Avoid.
+For example, here are two similar functions.
+Both use @code{and}, @var{symbol} and @code{guard}:
+
address@hidden
address@hidden
+(defun square-double-digit-p/OK (integer)
+ (pcase (* integer integer)
+ ((and n (guard (< 9 n 100))) (list 'yes n))
+ (sorry (list 'no sorry))))
+
+(square-double-digit-p/OK 9) @result{} (yes 81)
+(square-double-digit-p/OK 3) @result{} (no 9)
address@hidden group
+
address@hidden
+(defun square-double-digit-p/WRONG (integer)
+ (pcase (* integer integer)
+ ((and n (guard (< 9 (incf n) 100))) (list 'yes n))
+ (sorry (list 'no sorry))))
+
+(square-double-digit-p/WRONG 9) @result{} (yes 81)
+(square-double-digit-p/WRONG 3) @result{} (yes 9)
address@hidden group
address@hidden example
+
address@hidden
+The difference is in @var{boolean-expression}:
address@hidden references @code{n} simply and directly,
+while @code{WRONG} references @code{n} with a side-effect,
+in the expression @code{(incf n)}.
+When @code{integer} is 3, here's what happens:
+
address@hidden
address@hidden The first @code{n} binds it to @var{expval},
+i.e., the result of evaluating @code{(* 3 3)}, or 9.
+
address@hidden @var{boolean-expression} is evaluated:
+
address@hidden
+start: (< 9 (incf n) 100)
+becomes: (< 9 (setq n (1+ n)) 100)
+becomes: (< 9 (setq n (1+ 9)) 100)
+becomes: (< 9 (setq n 10) 100)
+ ; @r{side-effect here!}
+becomes: (< 9 n 100) ; @address@hidden now bound to 10}
+becomes: (< 9 10 100)
+becomes: t
address@hidden example
+
address@hidden Because the result of the evaluation is @code{t},
address@hidden matches, @code{and} matches, and
+control passes to that clause's body forms.
address@hidden itemize
+
address@hidden
+Aside from the mathematical incorrectness of asserting that 9 is a
+double-digit integer, there is another problem with @code{WRONG}.
+The body form references @code{n} once more, yet we do not see
+the updated value---10---at all. What happened to it?
+
+To sum up, it's best to avoid side-effecting references to
address@hidden patterns entirely, not only
+in @var{boolean-expression} (in @code{guard}),
+but also in @var{expr} (in @code{let})
+and @var{function} (in @code{pred} and @code{app}).
@item address@hidden should all bind the same symbols'' (from @code{or}).
@c (what does it mean?)