SBCL warning that a variable is defined but never used - common-lisp

I'm getting a warning from the sbcl compiler, that a variable has been defined but is not used. And the compiler is right. I want to get rid of the warning, but don't know how to do it. Here is an example:
(defun worker-1 (context p)
;; check context (make use of context argument)
(if context
(print p)))
(defun worker-2 (context p)
;; don't care about context
;; will throw a warning about unused argument
(print p))
;;
;; calls a given worker with context and p
;; doesn't know which arguments will be used by the
;; implementation of the called worker
(defun do-cmd (workerFn context p)
(funcall workerFn context p))
(defun main ()
(let ((context ()))
(do-cmd #'worker-1 context "A")
(do-cmd #'worker-2 context "A")))
The do-cmd-function expects worker-functions that implement a specific interface f(context p).
The sbcl compiler throws the following warning:
in: DEFUN WORKER-2
; (DEFUN WORKER-2 (CONTEXT P) (PRINT P))
;
; caught STYLE-WARNING:
; The variable CONTEXT is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition

You need to declare that the parameter is intentionally ignored.
(defun worker-2 (context p)
(declare (ignore context))
(print p))
ignore will also signal a warning if you do use the variable. To suppress warnings in both cases, you can use the declaration ignorable, but this should only be used in macros and other such cases where it's not possible to determine whether the variable will be used at the point of its declaration.
In case you are not yet familiar with declare, note that it is not an operator, and instead can only appear in certain locations; in particular, it must be located before all forms in the defun body, though it can be either above or below a documentation string.

Related

Subtle Compiler Warning in SBCL When Compiling a Lambda Expression

I'd like some help with understanding an SBCL compiler warning message, which occurs when compiling a lambda expression. The lambda expression is temporarily stored as the symbol-value of a user-defined name, and the compiled function is subsequently stored under the name's symbol-function.
* (compile nil (symbol-value 'activate-connector-if!))
; in: LAMBDA (STATE ?CONNECTOR)
; (APPLY #'SOME
; (LAMBDA (WOULDWORK-PKG::?T1 WOULDWORK-PKG::?T2)
; (AND
; (GETHASH (+ 126 # #)
; (WOULDWORK-PKG::PROBLEM-STATE.IDB WOULDWORK-PKG::STATE))
; (GETHASH (+ 126 # #)
; (WOULDWORK-PKG::PROBLEM-STATE.IDB WOULDWORK-PKG::STATE))
; (LET (#)
; (WHEN VALUES #))
; (LET (#)
; (WHEN VALUES #))
; (NOT (EQL WOULDWORK-PKG::$HUE1 WOULDWORK-PKG::$HUE2))))
; NIL NIL)
; --> MULTIPLE-VALUE-CALL SB-C::%FUNCALL SOME LET BLOCK SB-INT:DX-FLET FLET
; --> #:WRAPPER102 BLOCK LET
; ==>
; (SB-C::%FUNCALL #:G100 #:G99)
;
; caught WARNING:
; function called with one argument, but wants exactly two
; See also:
; The ANSI Standard, Section 3.2.2.3
;
; compilation unit finished
; caught 1 WARNING condition
#<FUNCTION (LAMBDA (STATE ?CONNECTOR)) {1002E32AAB}>
T
T
The warning corresponds to the two required arguments, but there is no information about where the function is being called from. However, there is only one possible place it can be called from, and a check verifies that it is being called with two arguments.
Since the program runs fine on all test cases in spite of this warning, at first I thought it meant the function is never being called. But a trace verifies it is being called properly a number of times with the correct arguments.
Is there any other way to get at what is generating the warning?
(LAMBDA (WOULDWORK-PKG::?T1 WOULDWORK-PKG::?T2) ...) requires 2 arguments, but it's being called with just 1 argument by SOME. When you convert the APPLY call to a normal function call, it looks like:
(some (lambda (?t1 ?t2) ...) '())
There need to be as many sequence arguments as arguments to the predicate function, but there's only one sequence and two arguments.
Maybe you meant to use FUNCALL rather than APPLY? APPLY treats its last argument as a list of arguments, so NIL is spread into no arguments.

How do you create an interpreted function in SBCL?

I want to create an interpreted function definition, not a compiled one.
SBCL manual says :
Variable: *evaluator-mode* [sb-ext] : Toggle between different evaluator
implementations. If set to :compile, an implementation of eval that
calls the compiler will be used. If set to :interpret, an interpreter
will be used.
So, I try to create a BAR function (which does not exist) :
(let ((sb-ext::*evaluator-mode* :interpret))
(defun bar (x) (+ x 1)))
But then, I check, and BAR is already compiled :
CL-USER> (compiled-function-p #'bar)
T
So, how do you create an interpreted version of BAR ?
The let form in your question only sets the evaluator mode at runtime. By then, the function has already been compiled.
You need to set it at load time and also make sure to load the file instead of compiling then loading it.
Try this:
In your-file.lisp:
;; at load time, set evaluator mode to interpret (before bar definition is met)
(eval-when (:load-toplevel :execute)
(setf sb-ext::*evaluator-mode* :interpret))
;;define your interpreted function
(defun bar (x)
(+ x 1))
;; set evaluator back to compile mode (optional)
(eval-when (:load-toplevel :execute)
(setf sb-ext::*evaluator-mode* :compile))
;;check if bar is a compiled function
(print (compiled-function-p #'bar)) ;;prints NIL
Then load it with (load "your-file.lisp") (this doesn't compile the file first).
I think that *evaluator-mode* is pretty inherently a global variable. For instance, if you do this:
> (setf sb-ext:*evaluator-mode* ':interpret)
:interpret
> (setf (symbol-function 'bar)
(lambda (x) x))
#<interpreted-function nil {10026E7E2B}>
> (compiled-function-p #'bar)
nil
you get an interpreted function. But if you do this:
> (setf sb-ext:*evaluator-mode* ':compile)
:compile
> (setf (symbol-function 'bar)
(let ((sb-ext:*evaluator-mode* ':interpret))
(lambda (x) x)))
#<function (lambda (x)) {52C3687B}>
> (compiled-function-p #'bar)
t
You don't. My take on this, which may be wrong, is that the value which is in effect at the start of each top-level form is what counts: once the system has decided that it's going to use the compiling-evaluator for a form then it can't change its mind.
And note that there is a complicated definition of 'top-level form', and in particular that when processing a file then in a form like
(let (...)
(x ...))
then (x ...) is not a top-level form.

Defining class and methods in macro

I'm still quite new to Common Lisp macros.
For an abstraction over a defclass with defgeneric I thought it'd be nice to make a macro.
A complitely naive implementation looks like:
(defmacro defgserver (name &key call-handler cast-handler)
"TODO: needs firther testing. Convenience macro to more easily create a new `gserver' class."
`(progn
(defclass ,name (gserver) ())
(defmethod handle-call ((server ,name) message current-state)
,(if call-handler call-handler nil))
(defmethod handle-cast ((server ,name) message current-state)
,(if cast-handler cast-handler nil))))
When used the error says that 'message' is not known.
I'm not sure. 'message' is the name of a parameter of defgeneric:
(defgeneric handle-call (gserver message current-state))
Using the macro I see a warning 'undefined variable message':
(defgserver foo :call-handler
(progn
(print message)))
; in: DEFGSERVER FOO
; (PRINT MESSAGE)
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::MESSAGE
Which when used has this consequence:
CL-USER> (defvar *my* (make-instance 'foo))
*MY*
CL-USER> (call *my* "Foo")
<WARN> [10:55:10] cl-gserver gserver.lisp (handle-message fun5) -
Error condition was raised on message processing: CL-GSERVER::C: #<UNBOUND-VARIABLE MESSAGE {1002E24553}>
So something has to happen with message and/or current-state.
Should they be interned into the current package where the macro is used?
Manfred
The problem, as mentioned, is that you are talking about different symbols.
However this is really a symptom of a more general problem: what you are trying to do is a sort of anaphora. If you fixed up the package structure so this worked:
(defgserver foo :call-handler
(progn
(print message)))
Then, well, what exactly is message? Where did it come from, what other bindings exist in that scope? Anaphora can be useful, but it also can be a source of obscure bugs like this.
So, I think a better way to do this, which avoids this problem is to say that the *-handler options should specify what arguments they expect. So instead of the above form you'd write something like this:
(defgserver foo
:call-handler ((server message state)
(print message)
(detonate server)))
So here, value of the :call-handler-option is the argument list and body of a function, which the macro will turn into a method specialising on the first argument. Because the methods it creates have argument lists provided by the user of the macro there's never a problem with names, and there is no anaphora.
So, one way to do that is to do two things:
make the default values of these options be suitable for processing into methods without any special casing;
write a little local function in the macro which turns one of these specifications into a suitable (defmethod ...) form.
The second part is optional of course, but it saves a little bit of code.
In addition to this I've also done a slightly dirty trick: I've changed the macro definition so it has an &body option, the value of which is ignored. The only reason I've done this is to help my editor indent it better.
So, here's a revised version:
(defmacro defgserver (name &body forms &key
(call-handler '((server message current-state)
(declare (ignorable
server message current-state))
nil))
(cast-handler '((server message current-state)
(declare (ignorable
server message current-state))
nil)))
"TODO: needs firther testing. Convenience macro to more easily
create a new `gserver' class."
(declare (ignorable forms))
(flet ((write-method (mname mform)
(destructuring-bind (args &body decls/forms) mform
`(defmethod ,mname ((,(first args) ,name) ,#(rest args))
,#decls/forms))))
`(progn
(defclass ,name (gserver) ())
,(write-method 'handle-call call-handler)
,(write-method 'handle-cast cast-handler))))
And now
(defgserver foo
:call-handler ((server message state)
(print message)
(detonate server)))
Expands to
(progn
(defclass foo (gserver) nil)
(defmethod handle-call ((server foo) message state)
(print message)
(detonate server))
(defmethod handle-cast ((server foo) message current-state)
(declare (ignorable server message current-state))
nil))

How to use variables from the creator in an asynchronously called lambda in elisp? [duplicate]

I have never been able to come up with a method to penetrate the set-process-sentinel hierarchy with let-bound variables defined at the outset of the function -- only buffer-local or global variables can penetrate it. Let-bound variables can reach the first start-process, but that is as far as they can penetrate without being rejected due to being unrecognized -- let-bound variables defined at the outset of the function do not appear to be able to penetrate the section that begins with (lambda (p e) . . .. Can anyone think of a way to do it, including penetrating nested sentinels like in the example below?
(set-process-sentinel
(start-process
"my-process-name-one"
"*OUTPUT-BUFFER*"
"/path/to/executable"
"argument-one"
"argument-two"
"argument-three")
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process
"my-process-name-two"
nil ;; example of not using an output buffer
"/path/to/executable"
"argument-one"
"argument-two"
"argument-three")
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process . . . ))))))))
The problem is that Emacs Lisp variable bindings are dynamic by default. That is, when a function is evaluated, bound variables are looked up not in the environment where the function was defined, but in the environment where the function was called.
Emacs 24 or later supports lexical binding (that is, the function sees the variables that were bound around the function definition) natively, but since it alters the semantics of existing code you need to enable it explicitly. Usually this is done by adding a file local variable setting to the first line of the .el file:
;; -*- lexical-binding: t; -*-
Another alternative is to use lexical-let from the cl library. This works in earlier Emacs versions as well. Note that in this way you explicitly specify which variables should have lexical binding, so code such as (lexical-let ((foo foo)) ...) is not uncommon — foo is an existing variable which needs to be "carried over" into the function.
The following is an example using dynamic bindings:
(defun example-dynamic-fn ()
"Doc-string"
(interactive)
(let ((test-variable "Hello-world!"))
(set-process-sentinel
(start-process "process-one" "*one*" "echo" test-variable)
`(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process "process-two" "*two*" "echo" ,test-variable)
'(lambda (p e) (when (= 0 (process-exit-status p))
(start-process "process-three" "*three*" "echo" ,test-variable)
(set-process-sentinel
(start-process "process-four" "*four*" "echo" ,test-variable)
'(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process "process-five" "*five*" "echo" ,test-variable)
'(lambda (p e) (when (= 0 (process-exit-status p))
(message "test-variable: %s" ,test-variable)))))))))))))))
OK, I think I've got this now. The link above provides a good example; here's another in case anyone else has this difficulty:
;;; ensure VAR1 has no binding
(makunbound 'VAR1)
;;;
(defun f1 (&optional VAR1)
(interactive)
(unless VAR1
(set 'VAR1 "variable1"))
(pop-to-buffer "*test*")
; (lexical-let ( (VAR1 VAR1) ) ;;;
(set-process-sentinel
(start-process-shell-command "test"
"*test*"
(concat "echo " VAR1))
(lambda (process event)
(condition-case err
(when (string-match-p "finished" event)
(f2 VAR1))
(error
(princ
(format "Sentinel error: %s" err))))))
; ) ;;;
)
;;;
(defun f2 (&optional VAR2)
(interactive)
(unless VAR2
(set 'VAR2 "VARIABLE2"))
(print VAR2))
We load everything (with the lines in (f1) commented out) and run (f1). The value of VAR1 is passed to (f2) before the error occurs. The error (void-variable VAR1) appears to come from the scoping environment of (set-process sentinel PROCESS SENTINEL); VAR1 is not defined there even though it remains in scope for the SENTINEL ((lambda)) function.
Also using (set ) as above is not best practice when a variable is only meant to have scope local to the function.
If we uncomment the lines marked with ; then everything works as expected. Happily, we can pass the value through to another function, which prevents a long series of (set-process sentinel )s building up. It also allows us to generate processes with additional sub-processes, if required.
One of my mistakes was naming the SENTINEL as a discrete function, rather than keeping it inside the (lexical-let ) function. While the lexical-binding: t; approach is attractive, it will tend to break working code which relies on the standard (let ).

How to require keyword arguments in Common Lisp?

Given
(defun show-arg (a)
(format t "a is ~a~%" a))
(defun show-key (&key a)
(format t "a is ~a~%" a))
evaluating
(show-arg)
will lead to an error saying "invalid number of arguments: 0", where
(show-key)
will display a is NIL
How can I get SHOW-KEY to signal an error like SHOW-ARG does? Is there a way other than using (unless a (error "a is required")) in the function body? I am very fond of keyword arguments and use them constantly, and almost always want them to be required.
Keyword arguments are always optional, so you do need to manually check if they're given and signal an error if needed. It would be better to not require keyword arguments though. The compiler won't recognize them as required and thus won't given you an error message for missing arguments at compile time.
If you do want to require them, you can specify the arguments with a three element list; the first element being the argument, the second is the default value and the third is a variable that will be true if the argument was given. Checking the third element is better than checking the keyword itself, because then you can tell the difference between a NIL that was the default, and a NIL that the user gave as an argument.
(defun foo (&key (keyarg nil keyargp))
(unless keyargp (error "KEYARG is required."))
(* keyarg 2))
Edit
Now that I think about this a bit more, there actually is a way to get compile time errors for missing keyword arguments. Define a compiler macro for the function:
(defun foo (&key a b c d)
(* a b c d))
(define-compiler-macro foo (&whole whole &key (a nil ap) (b nil bp)
(c nil cp) (d nil dp))
(declare (ignore a b c d))
(unless (and ap bp cp dp)
(error "Missing arguments..."))
whole)
One possibility would be:
(defun foo (&key (arg1 (error "missing arg1 in call to function foo")))
arg1)
Using it:
CL-USER 80 > (foo)
Error: missing arg1 in call to function foo
1 (abort) Return to level 0.
2 Return to top loop level 0.
This will give an error at runtime, unfortunately not at compile time.

Resources