Question

When you perform a function call (myfunction ...) in emacs lisp, the byte compiler will warn if the function isn't known to be defined at compile time. This helps greatly with a top-down programming style, since then I can happily write

(defun foo (bar baz)
  (foo-filter-by-functon (lambda (a b) (equal (upcase a) (upcase b)))
   (foo-combine-values bar baz)))

When I compile the byte compiler tells me that I haven't yet defined or misspelled the two foo- functions.

However, if the lambda expression becomes complex some more restructuring makes sense, e.g.

(defun foo (bar baz)
  (foo-filter-by-functon 'foo-equal
   (foo-combine-values bar baz)))

Now there is a problem though... 'foo-equal is now a symbol and only at runtime when executing foo-filter-by-function a check whether 'foo-equal is defined will be executed. Something that normally is a compile-time warning suddenly has become runtime-error. The same problem applies for builtin higher-order functions such as mapcar, apply...

Is there some possibility to make the byte compiler recognize, that e.g. the first argument to mapcar should be a function and thus, when the argument is given as a symbol, check whether that symbol has a valid function definition, like it does with explicit (foo-equal ..) calls?

Note: The purpose is to allow making production code more readable, so solutions that require a change of each call to foo-filter-by-function or hackish code in its definition are not acceptable solutions. An example of such a counter-productive solution would be

(defun foo (bar baz)
  (foo-filter-by-functon (lambda (a b) (foo-equal a b)) ... )
   (foo-combine-values bar baz)))

or

(defun foo (bar baz)
  (foo-filter-by-functon foo-equal
   (foo-combine-values bar baz)))

(defconst foo-equal (lambda (a b) ...)

since both result in inferior code readability at least subjectively.

Was it helpful?

Solution

You want to use #'foo-equal instead of 'foo-equal so as to tell the compiler that you're not just talking about the foo-equal symbol but about the foo-equal function.

OTHER TIPS

It seems to me that you're touching the static/dynamic language question.

The code

(defun foo (bar baz)
  (foo-filter-by-functon 'foo-equal
   (foo-combine-values bar baz)))

is perfectly legal lisp code which stems from its flexibility. There are legal situations when foo-equal need not be defined. I think what you meant was

(defun foo (bar baz)
  (foo-filter-by-functon #'foo-equal
   (foo-combine-values bar baz)))

It's still legal lisp code. There could be situations, although less, when foo-equal need not be defined.

The main point

It's foo-filter-by-functon that decides whether its argument will be called or not, so it's logical that it should check the argument before calling: maybe something like this:

(defun-carefully
    `(defun foo-filter-by-function (fun lst)
       (cl-remove-if-not fun lst)))

Where defun-carefully is a macro that will define the function, and store in some dict that it calls its first argument. How did it know that it calls its argument? It looked up in the same dict that cl-remove-if-not calls its argument.

And if all defuns are wrapped with this macro, maybe it's possible to get to the warnings that you want. Maybe it's possible to redefine defun temporarily with macrolet for the duration of eval-buffer.

Still it's a lot of work. I hope someone else does / did it:)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top