Are there function prototypes in Common Lisp?

I have been programming lisp in general for a little while, and throughout my experience with lisp, I have yet to see any function / macro that acts like something similar to function prototypes in C or C ++.

Currently, I have to be very careful about ordering my functions, otherwise, when I try to call a function from another, lisp says that the function "does not exist" because it is defined later in the file. Is there any way around this? Can I declare all my function prototypes at the top of the file and the full definitions below?

+5
source share
3 answers

Announcement and Proclamation

You can use declaim to globally declare that a certain thing has a certain type of function. For example, see what happens first if you define foo1 , which calls undefined baz (in SBCL):

CL-USER> (defun foo1 () (baz)) ; in: DEFUN FOO1 ; (BAZ) ; ; caught STYLE-WARNING: ; undefined function: BAZ ; ; compilation unit finished ; Undefined function: ; BAZ ; caught 1 STYLE-WARNING condition FOO1 

Now add a recitation that says baz is a function with no arguments and returns something. Obviously, you could add more type information if you want, but this will at least provide arity and knowledge that the baz function is a function.

 CL-USER> (declaim (ftype (function () t) baz)) ; No value 

Now, when you define foo2 , which also calls baz , you will not receive a warning:

 CL-USER> (defun foo2 () (baz)) FOO2 

Declaim is a macro, but if you need to create some of these things at runtime, you can use decllaim , which is a function. For instance,

 CL-USER> (dolist (f '(square cube)) (proclaim `(ftype (function (number) number) ,f))) NIL CL-USER> (defun add-square-and-cube (xy) (+ (square x) (cube y))) ADD-SQUARE-AND-CUBE 

However, this is not a very idiomatic Common Lisp. It is much more common to put the desired code in a file and then compile this file and load it. If this is not possible for some reason, this will work, but you should consider other options for loading your code, if available.

Mute Warnings

It's also worth noting that while the SBCL will take a hint of proclaiming or reciting and freezing the warning of the undefined function, the function is still actually undefined. Other implementations (e.g. CLISP) will continue to issue a warning about the undefined function.

I really do not recommend the following approach, because warnings exist for some reason, but you can choose to silence warnings when evaluating code. For example, in CLISP we get a warning when compiling using undefined functions:

 CL-USER> (compile nil (lambda () (baz))) WARNING: Function BAZ is not defined #<COMPILED-FUNCTION NIL> 1 1 

We can bind a handler that will drown out any warnings that occur when evaluating the form:

 CL-USER> (handler-bind ((warning (lambda (x) (muffle-warning x)))) (compile nil (lambda () (baz)))) #<COMPILED-FUNCTION NIL> 1 1 

This also has ow warnings, because the type of warning you might get to compile the undefined function reference might be different, and what muffles the warning might be different.

+12
source

As Rainer noted, you can ignore this problem if the direct link is in the same compilation unit. But this will not help if the direct link crosses the compilation units. This is usually a sign that your code is poorly layered. Does a low level code allow you to call a higher level code? Well, people will say that low-level code provides a hook for high-level code.

This says that of course I saw and wrote code that had this problem. Spaghetti code, yum! This can occur if you start breaking up large source files into smaller ones. The compilation unit is usually a single file. But look at the compilation unit. I don’t remember that asdf does not provide easy access though.

I don't know if the Joshua solution will use declaration granting to work in all CL implementations. My memory is that when I had to solve this problem many years ago, we had to implement something rougher , we would let the function stand in the definition, and then crack the way to suppress definition warnings.

No doubt cl-launch could be used to see if the Joshua solution works across a wide range of implementations.

+4
source

You can define something as a universal function before you define any of its methods. So if you write

(defgeneric foo (xyz))

then any function that calls FOO will see a particular function (although without any methods). Then the function body can be added later as a method

(defmethod foo (xyz) ;; function body ...)

0
source

Source: https://habr.com/ru/post/1201484/


All Articles