Subject: bug#40968: 28.0.50; (apply nil)

From: Drew Adams <[email-masked]>
Date: Wed, 6 May 2020 14:35:41 -0700 (PDT)

> To my mind the nicest change would be to handle the two error cases,
> and keep everything else the same.
> 
> 1. (apply nil) would signal an error.
> 2. (apply FUNC) would be equivalent to funcall, rather than signalling
>     an error, when (functionp FUNC) -- or perhaps just (not (consp
>     FUNC)).
> 3. (apply LIST) would remain equivalent to (apply (car LIST) (cdr
>     LIST))
> 
> I don't feel strongly about #2.  It seems like a nice enhancement to
> me,
> but if others feel that would be cause problems then I wouldn't argue.
> Existing uses of that in the wild are obviously signalling errors at
> present, so offhand it doesn't seem to me like a dangerous change, and
> it would match the existing signature.
> 
> #3 just seems like the only useful thing that apply could possibly do
> with a single list argument, so I'd definitely keep that.
> 
> #2 and #3 are surely both convenient for generated code which doesn't
> know how many arguments it's going to be dealing with.
> 
> I would still use (FUNCTION &optional ARGS) as the signature, and just
> document what happens when FUNCTION is actually a list.

What's wrong with doing what Common Lisp does
(apparently, per the doc'd signature)?

(apply FUNCTION first-arg &rest other-args)

The first arg to `apply' is required, and
must be a function.

The second arg to `apply' is required.
Any arg after the second is optional.

The last arg to `apply' must be a list.
(This is true even if it is the second arg.)
It can be nil.

* If the last arg is the second arg, then its
  elements are the args passed to FUNCTION.
  (If it is the empty list then FUNCTION must
  be nullary.)

* If the last arg is not the second arg, then
  its elements are the Nth args for FUNCTION,
  where N = 1+ the element index.  FUNCTION
  must be able to accept M args, where M = 1+
  the number of elements in the last arg.

"Must" means an error is raised if not so.

(apply)          => error
(apply ANYTHING) => error

(apply FUNCTION '(x)   ) => (funcall FUNCTION x)
 ; last arg: singleton list of args

(apply FUNCTION   x  ()) => (funcall FUNCTION x)
 ; first arg: x
 ; last arg: empty list of other args

(apply FUNCTION  ()    ) => (funcall FUNCTION)
 ; last arg: empty list of args

(apply FUNCTION  ()  ()) => (funcall FUNCTION nil)
 ; first arg nil
 ; last arg: empty list of other args