On Mon, 2006-03-13 at 17:11 +0000, Luís Oliveira wrote:
I think this isn't a good idea. Here's an example:
(defmethod expand-to-foreign-dyn (value var body (name (eql :string))) (if <string's size is appropriate for stack allocation> `(with-foreign-string (,var ,value) ,@body) *runtime-translator-form*))
Surely we want free-translated-object to be called in this case.
It will be. The problem appears in the current rules for providing a fallback when expand-to-foreign-dyn is not provided. This is exemplified in the new tests: one answers T and the other answers NIL, when both should answer T or NIL.
According to node "Optimizing Type Translators", several forms are guaranteed to use `expand-type-to-foreign' even when they want the semantics of foreign-dyn expansion, when such an explicit expansion is unavailable.
I ran into this problem while eliminating *runtime-translator-form* from the interface. I have a patch that implements option 1; it can be trivially changed to implement either other option, however.
1) Remove the guarantee; fall back on the translate-* gfs when no foreign-dyn expansion is available. This is currently implemented by answering *runtime-translator-form* from a foreign-dyn expansion.
2) Specify that the form answered by expand-type-to-foreign must have the exact same semantics as those evaluated by calling translate-type-to-foreign, thereby meeting a congruence with CL compiler-macros. This means that it returns an ALLOC-PARAM as its second value, which is then passed to the gf free-type-translated-object in an unwind-protect.
3) Specify that the form answered by expand-type-to-foreign, when evaluated, answers a value that does not need to be freed. This is currently implemented by not providing a foreign-dyn expansion method, in the case of foreign-typedefs anyway.
I prefer 1 to 2 because the point of the expand-* interface is to avoid gf calls and stuff. If you let users expect optimization in all cases without providing foreign-dyn expansions, they may not expect that the result may still contain an unwind-protect whose cleanup form calls a gf. I would rather say that the user can only expect perfect optimization by providing explicit to-foreign, from-foreign, and to-foreign-dyn expansions.
This does not preclude providing a function to trivialize overriding the default behavior in favor of option 3, if the type-defining user so chooses.
(defun simple-foreign-dyn-expansion (value var body typename) "Answer a form to be answered from `expand-to-foreign-dyn', where VALUE, VAR, BODY, and TYPENAME are the respective args to the aforementioned GF. The result will not be freed." `(let ((,var ,(expand-type-to-foreign value (parse-type typename)))) ,@body))