[cffi-devel] Re: Type translators

James Bielman jamesjb at jamesjb.com
Thu Aug 4 03:57:03 UTC 2005


Luis Oliveira <luismbo at gmail.com> writes:

> First thing I'm changing is :in/:return, the names don't make sense
> when we think about callbacks, the :return translation is applied for
> the arguments and :in for the callback's return value. So I picked
> :to-c and :from-c. Can someone suggest better names?
>
> And this is how my interface would look like:
>
>    (define-type-translation (boolean :int)
>      "Converting between C ints and Lisp booleans."
>      :to-c (if &value 1 0)
>      :from-c (if (zerop &value) nil t))
>
> It takes care of the defctype unless the first arg isn't a list. If it
> were just 'boolean' defctype woudn't be used (eg. when defining a
> type-translating for a struct type). Hmm, is this extra syntax re
> defctype overkill?

I think this is a good improvement.  I always knew the type translator
syntax was too complicated but never got around to simplifying it.

As for the DEFCTYPE syntax, how about another keyword argument:

  (define-type-translation boolean
    "doc"
    :c-type :int
    :to-c ...
    :from-c ...)

> Also it sets up &value with symbol-macrolet.

I must admit I'm not wild about using &symbols as placeholders inside
these expansions, as I think that's a naming convention best left
unique to lambda list keywords.

Here are some alternative syntaxes (besides just renaming the symbol
macros), I'm sure there are more:

  ;; Use special variables instead of symbol macros:
  :in (let ((*var* (foreign-string-alloc *value*)))
        (unwind-protect
            (progn *body*)
          (foreign-string-free *var*)))

  ;; Use MACROLET, sort of like CALL-NEXT-METHOD:
  :in (let (((var) (foreign-string-alloc (value))))
        (unwind-protect
            (progn (body))
          (foreign-string-free (var))))

  ;; IMO the cleanest, but also verbose, using a function
  ;; that returns the form using backquote:
  :in (lambda (var value body)
        `(let ((,var (foreign-string-alloc ,value)))
           (unwind-protect
               (progn , at body)
             (foreign-string-free ,var))))

> Here we have an extra translation :in, used when we are actually
> passing something to a foreign function (the :to-c translation is
> used, in case :in is undefined). Here we have to explicitly write the
> unwind-protect, I think the translation becomes more readable this
> way. :in also sets up a few more (symbol-)macros, &var and &body whose
> meaning should be obvious.

> Getting to decide where &body goes (ie. not having to be restricted to
> a unwind-protect form as before) gives us the ability to do this:
>
>    (define-type-translation (string :pointer)
>      "Converting between C and Lisp strings."
>      :in (with-foreign-string (&var &value)
>            (&body))
>      :to-c
>      (foreign-string-alloc &value)
>      :from-c
>      (foreign-string-to-lisp &value))
>
>
> This way the string is stack allocated (if the lisp supports this).

Yes, this was one of my big complaints about my current design. :-)

> In this last example, I indented the code in a different way, I'm not
> yet happy with the syntax, any comments or suggestions regarding
> syntax, naming, etc.. will be most appreciated.

:IN might be better named something that makes it clear that it is
fulfilling a similar purpose to :TO-C except it is used only in the
special circumstance of passing arguments to a function.  Maybe
:TO-C-ARG or something...

James



More information about the cffi-devel mailing list