2013/8/1 Stefan Monnier > >>> 1. Has to be done, though maybe through a macro, for every higher-order > >>> function. > >> Note that macroexp.el already has special handling for the main > >> higher-order functions (to warn about '(lambda ...)). So it could be > >> implemented there. > > I presume the list of “main higher-order” functions is hard-coded > > then, isn't it? > > Currently, yes. It could be moved from macroexp.el's main loop to > a bunch of compiler-macros (the code predates the introduction of > compiler macros in core Elisp), if needed. > > > Is there a symbol property or "declare" form to mark specific > > arguments as function arguments, to have the same warnings for higher > > order functions from 3rd party libraries, too? Similar to how > > "docstring" arguments for macros are handled? > > No, and I think it would be overkill. But 3rd party can also use > a compiler-macro to turn the ' into a #'. > > The approach I use for '(lambda ...) is to emit warnings in the common > cases, so that coders will slowly learn, which then benefits all cases. > > For '(lambda ...) that works well, because removing the ' (or using #') > is often useful (making it possible to byte-compile the code, or using > lexically bound vars), but for single quoted symbols, the benefit is > a lot less clear ("turn 'foo into #'foo to get rid of the silly new > warning" only to then get another warning because the compiler doesn't > understand that `foo' will very much exist by the time we try to call it). > > > Stefan > I have written an implementation of the compile-time check, see the attached patch to "lisp/bytecomp.el". Since I also introduced as new declare form for `defun', I have also attached a patch to "doc/functions.texi". The code handles both the cases (function SYMBOL) and (quote SYMBOL). In the latter case it requires a symbol property "higher-order-arguments" to be set, which should preferably be done by a declare form, but for now is implemented by checking for a set of common functions (apply, funcall, all functions I found starting with "map" or "cl-map") for the property and setting it if it is not yet set. The value of the property should be a list of integers, which give the positions of the arguments that are expected to be functions, counting from 0. If the patch becomes part of the emacs sources, I can also provide a patch that adds the needed declare forms to the various definitions, though I don't know how to do it for functions defined in the C-code such as `mapcar'. Currently such a function (in this case requiring lexical binding) definition would read (defun my-combine (func1 func2) (declare (higher-order-arguments 0 1) (lambda (arg) (funcall func1 (funcall func2 arg)))) or (defun my-map (func list) (declare (higher-order 0)) (mapcar func list)) I was thinking of allowing to declare the number of arguments the function will be passed, but didn't have the time for that detail (yet?). One thing I am not sure about: I define the handler for the declare form in "bytecomp.el", hence the handler is not known before loading that file. When loading a file from source the declare form will therefore cause a warning. When compiling it doesn't seem to cause issues though. I couldn't define the handler in "byte-run.el" however, as when I added it to the declaration of `defun-declaration-alist', it would suddenly be missing again during compilation. - Klaus