[cffi-devel] Getting more out of the type system (was Re: cffi macro suggestion)

Luís Oliveira luismbo at gmail.com
Sun Mar 26 13:26:33 UTC 2006


hbabcockos1 at mac.com writes:
> (pl-defcfun ("c_plmesh" plmesh) :void
>   (x *plflt nx)
>   (y *plflt ny)
>   (z **plflt (nx ny))
>   (nx plint)
>   (ny plint)
>   (opt plint))

This is interesting and I think this is doable using plain defcfun and
CFFI's type system. If it's not, it should.

(in-package #:cffi)

(defclass my-array (foreign-type-alias)
  ((dimensions :initarg :dimensions :reader dimensions)))

(define-type-spec-parser my-array (type &rest dimensions)
  (make-instance 'my-array
                  :actual-type (parse-type type)
                  :dimensions dimensions))

(defmethod expand-type-to-foreign-dyn (value var body (self my-array))
  `(let ((,var (generate-array (list ,@(dimensions self)) ,value)))
     (unwind-protect
         (progn , at body)
       (free-array ,var))))

(defcfun "plmesh" :void
  (x (my-array :float nx))    ; tk me a whl to fgr that plflt
  (y (my-array :float ny))    ; probably means float, heh
  (z (my-array :float nx ny))
  (nx :int)
  (ny :int)
  (opt :int))

The macro expansion of the DEFCFUN above looks something like this:

(DEFUN PLMESH (X Y Z NX NY OPT)
  (LET ((#:G1046 (GENERATE-ARRAY (LIST NX) X)))
    (UNWIND-PROTECT
         (PROGN
           (LET ((#:G1047 (GENERATE-ARRAY (LIST NY) Y)))
             (UNWIND-PROTECT
                  (PROGN
                    (LET ((#:G1048 (GENERATE-ARRAY (LIST NX NY) Z)))
                      (UNWIND-PROTECT
                           (PROGN
                             (LET ((#:G1049 NX))
                               (LET ((#:G1050 NY))
                                 (LET ((#:G1051 OPT))
                                   (VALUES (%FOREIGN-FUNCALL
                                            "plmesh"
                                            :POINTER #:G1046
                                            :POINTER #:G1047
                                            :POINTER #:G1048
                                            :INT #:G1049
                                            :INT #:G1050
                                            :INT #:G1051
                                            :VOID))))))
                        (FREE-ARRAY #:G1048))))
               (FREE-ARRAY #:G1047))))
      (FREE-ARRAY #:G1046))))


So, again, your example is quite interesting because it reminds me that
we should export all of the functionality of the type system. In
particular, the ability to get at type arguments in the type translators
seems quite useful.

(Also, Greg Pfeil has been running into the "limitation" that typedefs
don't behave like other user-defined types, such as structs and enums,
with regard to type translators.)

I've been thinking about how to nicely export this kind of functionality
to the user and this is what I came up with:

  ;;; thin wrapper around defclass with cffi::foreign-type as a super
  (define-foreign-type foo ()
    (slot1
     slot2)
    (:documentation "foo"))

  (defmethod parse-type ((name (eql 'foo)) args)
    (destructuring-bind (bar &key baz)
        args
      (make-instance 'foo ...)))


Possibly with some syntactic sugar over that defmethod:

  (define-parse-method foo (bar &key baz)
    (make-instance 'foo ...))


And the default method could be something like this:

  (defmethod parse-type (name args)
    (apply #'make-instance name args))


Then we need to think about how typedefs would fit into this more
CLOS-based type interface. Hopefully, we'd unify the
translate/expand-[type-|]to/from-foreign{-dyn} pairs (ie. those with
"type" in the name and those without).

Last but not the least, your example reminds me that we need to add
an array type and to finish the shareable vectors interface, etc...

So, thanks! :-)

-- 
Luís Oliveira
luismbo (@) gmail (.) com
Equipa Portuguesa do Translation Project
http://www.iro.umontreal.ca/translation/registry.cgi?team=pt




More information about the cffi-devel mailing list