On Sat, Aug 27, 2011 at 10:11 PM, Liam Healy lnp@healy.washington.dc.us wrote:
So you're suggesting retaining the :constructor and :deconstructor arguments to defcstruct? It seems like a custom translate-*-foreign may be more compatible with existing CFFI, though I guess a compatibility expansion might be convenient.
No, that's not what I meant. Let's take your COMPLEX example. That should make things clearer.
(defcstruct (complex :class complex-type) (real :double) (imag :double))
(defmethod translate-to-foreign ((value complex) (type complex-type)) (let ((p (foreign-alloc 'complex))) (with-foreign-slots ((real imag) p 'complex) (setf real (realpart value) imag (imagpart value))) (values p t)) ; second value is passed to FREE-TRANSLATED-OBJECT
(defmethod free-translated-object (value (p complex-type) freep) (when freep (foreign-free value)))
(defmethod translate-from-foreign (value (type complex-type)) ...)
(defcfun (complex-conjugate "gsl_complex_conjugate") complex (c (:by-value complex)) ; or something like that.
;; we can then call it like this:
(complex-conjugate #c(3.0d0 4.0d0)) #C(3.0 -4.0)
;; what I was proposing is that one could /also/ call it like this:
(with-foreign-object (p 'complex) (with-foreign-slots ((real imag) p 'complex) (setf real 3.0 imag -4.0)) (complex-conjugate p))
In summary, we're always dealing with struct pointers, but the function declaration will determine whether that struct will be passed by value or not. Does that make sense?
My follow-up question was: is this too subtle? Should we make this more explicit? E.g.:
(with-foreign-object (p 'complex) (with-foreign-slots ((real imag) p 'complex) (setf real 3.0 imag -4.0)) (complex-conjugate (struct-pointer-value p)))
Doesn't look too pretty.
For a default conversion assuming a structure on the lisp side, I'm not sure how to iterate over the structure. Maybe MOP has something? I do have iterate-foreign-structure. If I assume a list or vector on the lisp side, then I could iterate through it.
If we add such a feature, I guess the Lisp structure (or class) should be defined by defcstruct itself.
If I define a specializer for a particular cstruct, what should the class be? This looks like a type name, not the actual object that's passed as the second argument 'type, so I presume it should be an eql specializer on the name, but I admit I'm getting confused by this. In any case I think the :class option to defcstruct won't always work because it does a defclass, I need something like :existing-class that would just do a find-class.
Hopefully my example with COMPLEX-TYPE illustrates how that works. The type argument gets an instance of COMPLEX-TYPE, which is the result of (parse-type 'complex). Was it clear?
Cheers,