]> git.eshelyaron.com Git - emacs.git/commitdiff
Handle single-argument `apply' consistently (bug#40968)
authorPip Cet <pipcet@gmail.com>
Sun, 27 Sep 2020 14:59:00 +0000 (16:59 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Sun, 27 Sep 2020 14:59:00 +0000 (16:59 +0200)
* src/eval.c (Fapply): Handle (apply nil) without crashing.
Document single-argument form.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-apply): Don't attempt
to optimize single-argument apply.
* doc/lispref/functions.texi (Calling Functions): Document
single-argument apply.  Provide example (bug#40968).

doc/lispref/functions.texi
lisp/emacs-lisp/byte-opt.el
src/eval.c

index 26b212d05eb15fa6e6d4e3a443e30f10151987d6..e8e22078d9bbd354eae32307251d26bc1d1c2d78 100644 (file)
@@ -762,6 +762,11 @@ arguments, rather than a single list.  We say that @code{apply}
 @dfn{spreads} this list so that each individual element becomes an
 argument.
 
+@code{apply} with a single argument is special: the first element of
+the argument, which must be a non-empty list, is called as a function
+with the remaining elements as individual arguments.  Passing two or
+more arguments will be faster.
+
 @code{apply} returns the result of calling @var{function}.  As with
 @code{funcall}, @var{function} must either be a Lisp function or a
 primitive function; special forms and macros do not make sense in
@@ -789,6 +794,11 @@ primitive function; special forms and macros do not make sense in
 (apply 'append '((a b c) nil (x y z) nil))
      @result{} (a b c x y z)
 @end group
+
+@group
+(apply '(+ 3 4))
+     @result{} 7
+@end group
 @end example
 
 For an interesting example of using @code{apply}, see @ref{Definition
index 8a6c0b9a7fabafc096a85d3e0dfaa4bf40320c39..65e4e446266f11f3c9e9ce99d0363d4b5a6dd778 100644 (file)
 (defun byte-optimize-apply (form)
   ;; If the last arg is a literal constant, turn this into a funcall.
   ;; The funcall optimizer can then transform (funcall 'foo ...) -> (foo ...).
-  (let ((fn (nth 1 form))
-       (last (nth (1- (length form)) form))) ; I think this really is fastest
-    (or (if (or (null last)
-               (eq (car-safe last) 'quote))
-           (if (listp (nth 1 last))
-               (let ((butlast (nreverse (cdr (reverse (cdr (cdr form)))))))
-                 (nconc (list 'funcall fn) butlast
-                        (mapcar (lambda (x) (list 'quote x)) (nth 1 last))))
-             (byte-compile-warn
-              "last arg to apply can't be a literal atom: `%s'"
-              (prin1-to-string last))
-             nil))
-       form)))
+  (if (= (length form) 2)
+      ;; single-argument `apply' is not worth optimizing (bug#40968)
+      form
+    (let ((fn (nth 1 form))
+         (last (nth (1- (length form)) form))) ; I think this really is fastest
+      (or (if (or (null last)
+                 (eq (car-safe last) 'quote))
+             (if (listp (nth 1 last))
+                 (let ((butlast (nreverse (cdr (reverse (cdr (cdr form)))))))
+                   (nconc (list 'funcall fn) butlast
+                          (mapcar (lambda (x) (list 'quote x)) (nth 1 last))))
+               (byte-compile-warn
+                "last arg to apply can't be a literal atom: `%s'"
+                (prin1-to-string last))
+               nil))
+         form))))
 
 (put 'funcall 'byte-optimizer #'byte-optimize-funcall)
 (put 'apply   'byte-optimizer #'byte-optimize-apply)
index 5d3c32326db79ace45f64c603fe21fb2cae1678b..c34c11828c56bcfaefa535c7a21905838182274a 100644 (file)
@@ -2371,6 +2371,8 @@ eval_sub (Lisp_Object form)
 DEFUN ("apply", Fapply, Sapply, 1, MANY, 0,
        doc: /* Call FUNCTION with our remaining args, using our last arg as list of args.
 Then return the value FUNCTION returns.
+With a single argument, call the argument's first element using the
+other elements as args.
 Thus, (apply \\='+ 1 2 \\='(3 4)) returns 10.
 usage: (apply FUNCTION &rest ARGUMENTS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
@@ -2381,6 +2383,10 @@ usage: (apply FUNCTION &rest ARGUMENTS)  */)
   Lisp_Object fun = args[0];
   USE_SAFE_ALLOCA;
 
+  if (nargs == 1)
+    /* Special case: FUN is really a list of (FUNCTION . ARGS).  */
+    return CALLN (Fapply, CAR (fun), CDR (fun));
+
   ptrdiff_t numargs = list_length (spread_arg);
 
   if (numargs == 0)