On 05/09/2011 01:49 PM, Martin Simmons wrote:
On Sun, 08 May 2011 14:39:41 +0200, Nitralime  said:
Using a finalizer seems to be a possible way to go. But I'm not sure how
this can be done by just using the finalizer parameters "object" and 
"function"
where "function" can't reliablely access "object" (cf. documentation of 
finalizer
in "trivial-garbage"  package)!!

Any help and feedback is very much appreciated!
IMHO, attempting to transparently wrap a foreign object with a CLOS object is
not a good design.

Using a finalizer is dangerous because it is difficult to guarantee that the
Lisp wrapper object is retained for the correct lifetime.

For example, consider

(defstruct table
  foreign-pointer)

(defun allocate-table ()
  (make-table :foreign-pointer (foreign-allocate-table)))

(defun allocate-and-munge-table ()
  (let ((table (allocate-table)))
    (foreign-munge-table (table-foreign-pointer table))))

The compiler might not keep the variable "table" alive during the call to the
foreign function foreign-munge-table.  As a result, the Lisp table object
might be gc'ed in another thread while the foreign code is accessing it.

Consider the following sample (pseudo-)code:
----------------------------------------------------------
(defclass table ()
  ((table-pointer :initarg :handle :accessor handle-of)))

(defmethod initialize-instance :after ((self table) &key)
   (let ((table-pointer (handle-of self)))
        (tg:finalize self (lambda () (foreign-destroy-table table-pointer)))))

(defmethod get-row ((t table) index)
   (transform-to-lisp-vector (foreign-get-row (hadle-of t) index)))

(defmethod move-to ((t table) index)
   (foreign-move-to (handle-of t) index))
.....
----------------------------------------------------------

Now consider a function which creates a table instance
and puts it into a result plist (and has probabely some side effects):

(defun call-a-foreign-function (.....)
   (let (....)
        ....
        <call a foreign function which allocates a table object
         and returns a-foreign-table-pointer>
        ....
        (let ((result-table (make-instance 'table :handle a-foreign-table-pointer))
              (...))
             ...
             ...
             '(:id   ...
               :tab  result-table
               :msg  ...
               ...))))

The question is now what will happen if you do just

    (call-a-foreign-function ...)

or something like this

    (getf (call-a-foreign-function ...) :id)

I assume that the unreachable object 'result-table' will be garbage collected,
and the finalization will free the corresponding C table object!

Do you see any misconception (resp. potential danger) here?

Regards
Nik