No longer mark some functions as pure

Functions that guarantee a fresh return value should not be pure,
since their return value is likely to be mutated destructively:
https://bugs.gnu.org/64127

* NEWS.md (2.20.0): List affected functions.
* dash.el (-non-nil, -cons*, -snoc, -slice, -take, -take-last)
(-drop-last, -split-at, -interpose, -interleave, -repeat, -iota)
(-clone): No longer mark as pure.
* dev/examples.el (-powerset): Avoid mutating constant.

Fixes #405.
master
Basil L. Contovounesios 3 years ago
parent 96eaba028a
commit d5182da04c
No known key found for this signature in database
GPG Key ID: 205AB54A5D5D8CFF
  1. 9
      NEWS.md
  2. 26
      dash.el
  3. 2
      dev/examples.el

@ -35,6 +35,15 @@ See the end of the file for license conditions.
(-permutations '(1 1 2)) ; => '((1 1 2) (1 2 1) (2 1 1)) (-permutations '(1 1 2)) ; => '((1 1 2) (1 2 1) (2 1 1))
``` ```
- Several functions which are documented as returning a fresh, mutable
object (such as a copy of one of their arguments) are no longer
marked as `pure`. Pure functions called with constant arguments are
evaluated during byte-compilation; the resulting value is an
immutable constant, and thus unsafe to modify destructively. The
functions in question are: `-clone`, `-cons*`, `-drop-last`,
`-interleave`, `-interpose`, `-iota`, `-non-nil`, `-repeat`,
`-slice`, `-snoc`, `-split-at`, `-take`, `-take-last`.
#### New features #### New features
- The function `-contains?` now returns the matching tail of the list - The function `-contains?` now returns the matching tail of the list

@ -607,7 +607,7 @@ Its anaphoric counterpart is `--keep'."
(defun -non-nil (list) (defun -non-nil (list)
"Return a copy of LIST with all nil items removed." "Return a copy of LIST with all nil items removed."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(--filter it list)) (--filter it list))
(defmacro --map-indexed (form list) (defmacro --map-indexed (form list)
@ -856,7 +856,7 @@ See also: `-splice', `-insert-at'"
The last 2 elements of ARGS are used as the final cons of the The last 2 elements of ARGS are used as the final cons of the
result, so if the final element of ARGS is not a list, the result result, so if the final element of ARGS is not a list, the result
is a dotted list. With no ARGS, return nil." is a dotted list. With no ARGS, return nil."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(let* ((len (length args)) (let* ((len (length args))
(tail (nthcdr (- len 2) args)) (tail (nthcdr (- len 2) args))
(last (cdr tail))) (last (cdr tail)))
@ -871,7 +871,7 @@ is a dotted list. With no ARGS, return nil."
This is like `cons', but operates on the end of list. This is like `cons', but operates on the end of list.
If any ELEMENTS are given, append them to the list as well." If any ELEMENTS are given, append them to the list as well."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(-concat list (list elem) elements)) (-concat list (list elem) elements))
(defmacro --first (form list) (defmacro --first (form list)
@ -1172,7 +1172,7 @@ modulo the length of the list.
If STEP is a number, only each STEPth item in the resulting If STEP is a number, only each STEPth item in the resulting
section is returned. Defaults to 1." section is returned. Defaults to 1."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(let ((length (length list)) (let ((length (length list))
(new-list nil)) (new-list nil))
;; to defaults to the end of the list ;; to defaults to the end of the list
@ -1247,7 +1247,7 @@ Return a copy of LIST if it contains N items or fewer.
Return nil if N is zero or less. Return nil if N is zero or less.
See also: `-take-last'." See also: `-take-last'."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(--take-while (< it-index n) list)) (--take-while (< it-index n) list))
(defun -take-last (n list) (defun -take-last (n list)
@ -1256,7 +1256,7 @@ Return a copy of LIST if it contains N items or fewer.
Return nil if N is zero or less. Return nil if N is zero or less.
See also: `-take'." See also: `-take'."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(copy-sequence (last list n))) (copy-sequence (last list n)))
(defalias '-drop #'nthcdr (defalias '-drop #'nthcdr
@ -1273,7 +1273,7 @@ Return a copy of LIST if N is zero or less.
Return nil if LIST contains N items or fewer. Return nil if LIST contains N items or fewer.
See also: `-drop'." See also: `-drop'."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(nbutlast (copy-sequence list) n)) (nbutlast (copy-sequence list) n))
(defun -split-at (n list) (defun -split-at (n list)
@ -1283,7 +1283,7 @@ new list of the first N elements of LIST, and DROP is the
remaining elements of LIST (not a copy). TAKE and DROP are like remaining elements of LIST (not a copy). TAKE and DROP are like
the results of `-take' and `-drop', respectively, but the split the results of `-take' and `-drop', respectively, but the split
is done in a single list traversal." is done in a single list traversal."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(let (result) (let (result)
(--each-while list (< it-index n) (--each-while list (< it-index n)
(push (pop list) result)) (push (pop list) result))
@ -1641,7 +1641,7 @@ elements of LIST. Keys are compared by `equal'."
(defun -interpose (sep list) (defun -interpose (sep list)
"Return a new list of all elements in LIST separated by SEP." "Return a new list of all elements in LIST separated by SEP."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(let (result) (let (result)
(when list (when list
(!cons (car list) result) (!cons (car list) result)
@ -1653,7 +1653,7 @@ elements of LIST. Keys are compared by `equal'."
(defun -interleave (&rest lists) (defun -interleave (&rest lists)
"Return a new list of the first item in each list, then the second etc." "Return a new list of the first item in each list, then the second etc."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(when lists (when lists
(let (result) (let (result)
(while (-none? 'null lists) (while (-none? 'null lists)
@ -3321,7 +3321,7 @@ backward compatibility and is otherwise deprecated."
(defun -repeat (n x) (defun -repeat (n x)
"Return a new list of length N with each element being X. "Return a new list of length N with each element being X.
Return nil if N is less than 1." Return nil if N is less than 1."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(and (>= n 0) (make-list n x))) (and (>= n 0) (make-list n x)))
(defun -sum (list) (defun -sum (list)
@ -3396,7 +3396,7 @@ Starts from START and adds STEP each time. The default START is
zero, the default STEP is 1. zero, the default STEP is 1.
This function takes its name from the corresponding primitive in This function takes its name from the corresponding primitive in
the APL language." the APL language."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(unless (natnump count) (unless (natnump count)
(signal 'wrong-type-argument (list #'natnump count))) (signal 'wrong-type-argument (list #'natnump count)))
(or start (setq start 0)) (or start (setq start 0))
@ -3628,7 +3628,7 @@ Non-branch nodes are simply copied."
The new list has the same elements and structure but all cons are The new list has the same elements and structure but all cons are
replaced with new ones. This is useful when you need to clone a replaced with new ones. This is useful when you need to clone a
structure such as plist or alist." structure such as plist or alist."
(declare (pure t) (side-effect-free t)) (declare (side-effect-free t))
(-tree-map #'identity list)) (-tree-map #'identity list))
;;; Combinators ;;; Combinators

@ -1363,7 +1363,7 @@ related predicates."
(-powerset '()) => '(()) (-powerset '()) => '(())
(-powerset '(x y)) => '((x y) (x) (y) ()) (-powerset '(x y)) => '((x y) (x) (y) ())
(-powerset '(x y z)) => '((x y z) (x y) (x z) (x) (y z) (y) (z) ()) (-powerset '(x y z)) => '((x y z) (x y) (x z) (x) (y z) (y) (z) ())
(let ((p (-powerset '()))) (setcar p t) (-powerset '())) => '(())) (let* ((l (list 1)) (p (-powerset l))) (setcar l 2) p) => '((1) ()))
(defexamples -permutations (defexamples -permutations
(-permutations '()) => '(()) (-permutations '()) => '(())

Loading…
Cancel
Save