Reputation: 189
It is difficult to find an appropriate title because I do not understand why I have the following issue.
When I require
my package, I would like to assign a specific function according to some packages. The idea is to set a variable as follow:
(cond ((find-package 'foo) (setf *special-function* #'foo:foo-function))
((find-package 'bar) (setf *special-function* #'bar:bar-function))
(t (warn "The package FOO or BAR is required to enable the special function.")))
Then, the evaluation of this piece of code returns:
There is no package named "FOO"
with CCL
Package FOO does not exist
with SBCL
The main reason I want to do that is that it exists different packages which provide the same function, and I want to let the user be free to make its own choice by loading the package FOO or BAR (with a preference according to the order in the condition clauses).
Upvotes: 2
Views: 226
Reputation: 51501
This almost looks like you want to define a wrapper function for functionality available under different names in different implementations.
Since, as Rainer wrote, we need to distinguish the cases already at read time, we can use reader conditionals for that. Conveniently, all implementations push their name onto *features*
, so that we can do it like this:
(defun special-function (&rest args)
#+sbcl (apply #'foo:foo-function args)
#+ccl (apply #'bar:bar-function args)
#-(or sbcl ccl) (error "not implemented))
If instead you want to allow different libraries to fill in your functionality, you can either rely on the user to load one of those before loading your system, if those libraries push their own symbols to *features*
, or you can define little wrapper systems that add the optional dependency:
Example: your (asdf) system is named yoursys
, then you could define another system yoursys/foo-backend
and yoursys/bar-backend
, both of which would set your special-function
to their respective implementations, and depend on the needed library.
Upvotes: 1
Reputation: 139251
Think about the execution/evaluation of the following form:
(if (find-package 'foo)
(foo:foo-function))
Lisp
Your error happens in phase 1: Reading. The form can't be read, when the package does not exist.
A typical way around it would be this:
(if (find-package 'foo)
(funcall (find-symbol "FOO-FUNCTION" "FOO")))
We are then looking up the symbol at runtime. Note that function and package names are by default in uppercase.
In your case you would need to call
(symbol-function (find-symbol "FOO-FUNCTION" "FOO"))
to get the function object. Note though that sometimes it's preferred to just get the symbol.
funcall
and apply
can call global functions as function object or as symbol:
(funcall 'sin 2.1d0)
or
(funcall #'sin 2.1d0)
Thus when the thing needs to be called later, a symbol offers another source of indirection and will point to the current definition, where the function object can also be an older version of the function.
Upvotes: 3