Hello!
TL;DR
=====
Is there some possibility to make the byte-compiler check,
whether functions passed to higher-order functions as a symbol are
defined at compile-time, e.g. my-function-1 in
(mapcar 'my-function-1 some-list)?
I know some (intrusive) solutions, but if there is a built-in solution
or at least an elegant solution I'd strongly prefer that one.
My use-case
===========
When I do programming in emacs lisp, I typically start top-down. In
that process I introduce functions about whose implementation I intend
to think later, and rely on the byte-compiler for pointing out
functions to be implemented.
That approach however breaks down, when using higher-order functions.
If I have a function
(defun my-function (strings)
(append (list "start")
(mapcar 'my-function-1 strings)
(list "end")))
the byte-compiler will not tell me, that the function is undefined.
What is normally a byte-compiler warning is now a runtime error. So
far I don't know a //good// workaround, though I tried some:
1. Don't use a name, write a lambda in-place. Downside: Seriously
reduces readability when `my-function-1' is complex or especially,
when it contains something like
(mapcar 'my-function-1
(delete nil
(mapcar 'my-function-2 strings)))
2. Use a combination of function and variable
...
(mapcar my-function-1 strings)
...
(defconst my-function-1 (lambda () ...
Downside: Uncommon, therefore probably hard to read for anyone else
(and probably for myself a year later).
3. Wrap into a lambda.
(mapcar (lambda (e) (my-function-1 e)) strings)
Upside: When `my-function-1' is a general function that needs
more than one argument, this construct seems to be an elegant
solution when using lexical binding.
Downside: When, like here, it takes only one argument, it is more
likely unnecessarily confusing.
4. Wrap the higher-order functions into macros that do the check at
compile time.
Downside: I cannot think of a way, that
- Preserves the interface, including parameter names, and thus
the readbility of the `describe-function' text.
- Is future proof in that it doesn't require changing the wrapper
code when the interface of the function is changed in a
backward-compatible way.
- Doesn't interfere with the runtime behaviour of interpreted code
(e.g. raising warnings only during compilation, but not when
interpreting the code).
kind regards, Klaus