Hello again,
This message was sent friday or so, it took a while to get to the mailing-list. Meanwhile, I've implemented this with some changes. Read on.
On 2006-feb-10, at 15:48, I wrote:
Generic Functions:
(macroexpand-type-to-foreign value-form var body type) (macroexpand-type-from-foreign value type) (macroexpand-to-foreign value-form var body type) (macroexpand-from-foreign value-form type)
A few questions:
- maybe expand-* instead of macroexpand-*?
I've changed 'macroexpand' to 'expand' as it was getting a bit verbose.
- *-to-foreign, as you can see is the equivalent to the previous :to-c-dynamic translation. Would we want to provide the equivalent of :to-c too?
Turns out that we really need to provide this, namely for the translation we do for callbacks' return values. So the generic functions are now:
(expand-type-to-foreign-dyn value-form var body type) (expand-type-to-foreign value-form type) (expand-type-from-foreign value-form type)
(expand-to-foreign-dyn value-form var body type) (expand-to-foreign value-form type) (expand-from-foreign value-form type)
If a to-foreign-dyn translation doesn't exist, it'll try to use to- foreign. (but not the other way around, of course).
As I said, I'm trying to keep this simple, so the way this works now is that one of these translators completely hijacks the normal translators. Namely, it wouldn't follow the typedef chain and apply all translators (what would it use the run-time ones? the macroexpanion-time ones? Also this would make it a bit harder to determine whether a given type has a translator. Right now, what I do is call macroexpansion-{to,from}-foreign and one of the default methods will return 'no-expansion if no method was specialized on the type.)
Apropos of this, I had a new idea. Providing a way to bail out of the expander similar to a compiler macro's "&whole form". The easiest way to do this would be with an :around method for the expand-type-* GFs binding a special variable to the usual form that calls the translators at runtime.
So, a silly optimization for the :string type could be something like this...
(defmethod expand-to-foreign-dyn (value var body (type (eql :string))) (if (and (constantp value) (stringp (eval value))) `(with-foreign-string (,var ,value) ,@body) *runtime-translator-form*))
... while still keeping the flexibility of the runtime translators for this type (eg. dispatching based on value).
One final question. We can guarantee that these are used in defcfun, foreign-funcall, defcallback. However, we can't make such guarantees for foreign-slot-value (or mem-ref/mem-aref). Would it be a good idea to use these translators in the respective compiler macros? I'm inclined to say yes.
I'm even more inclined to say yes. :-)