here are some more comments on the module.
o You use the EXPORTING package. This has the side-effect of exporting
all foreign functions, including the ones you wrap.
E.g. train vs. svm_train. This is confusing to the user.
The user MUST NOT use svm_train (prevent duplicate finalization).
o Similar for PREDICT-VALUES. svm_predict_values look like internal
IMHO, the package exports should reflect the functions intended to be
called and those only.
Likewise, I find FASTCGI::GETENV not such a nice solution. I understand
that the library author may fear conflicts with user's packages using
package "EXT" as a rationale for the choice.
Maybe that's a good exception to the above rule, maybe not.
Possibly instead of not using EXPORTING, a couple of well-chose UNEXPORT
would be great?
o Please turn the comments to make-problem about destroy-problem and
models into a documentation string. It's good to document contracts.
>guarding works in the other direction, I think.
>I want PROBLEM not to be GCed until MODEL is.
Another idea is again to use SET-FOREIGN-POINTER.
You can have all models share the pointer of the problem:
(set-foreign-pointer model problem)
Then problem cannot be finalized until all models are.
Of course, you must destroy the reference within destroy-model. SETF
VALID NIL is not enough for that. It's even wrong, since you'd have a
single shared pointer, you cannot use (SETF VALID) on the model or you'd
kill the problem. But you can act like C++ people: replace the model's
pointer with a pointer (to NULL or :COPY) and additionaly make that one
(defun destroy-model (model)
when validp model
;; unlink from pointer to problem and prevent further use
(setf (validp (set-foreign-pointer model :copy)) nil)
You may wish to experiment with that idea.
Beside that, I found the code looks very clean. I never tried it out,
though. I'm too much into static testing :-)