Luis Oliveira luismbo@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 ,@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