From: Hoehle, Joerg-C. <Joe...@t-...> - 2003-03-06 09:05:06
|
Sam Steingold wrote: >yuk. CLISP has %ELEMENT. Why not use ELEMENT for the exported >interface if it is to be different from %ELEMENT (or just rename >%ELEMENT to ELEMENT and export it if they are the same)? >ELEMENT* looks too much like MEMBER* in Emacs-Lisp. They are not the same. Element has been a macro providing compile-time error checking since day 1 of the FFI. I don't want to change that. ELEMENT place indices* -> value What I want to introduce is a function operating on a foreign-variable object. ELEMENT* fv indices* -> value I choose a trailing star to indicate proximity to the macro. My Emacs-20.7 does not have member*. A trailing or preceding % has a long Lisp history of "system-internal - don't dare to touch" which is not suitable for an exported interface. BTW, one does not see much of a difference with ELEMENT. Let's talk about CAST instead. CAST additionaly takes a foreign type description. I realized yesterday that I forgot talking about another advantage of ELEMENT/CAST etc.: so far they successfully managed (for better or worse) to hide the internal foreign type representation from the programmer. I want to define a lower-level interface where this becomes visible. CAST place foreign-type -> place ; well-known, no change (CAST dest `(c-array uint8 ,actual)) CAST* foreign-variable internal-type -> foreign-variable (CAST* dest-fv (PARSE-C-TYPE `(c-array uint8 ,actual))) I actually don't want (CAST* dest-fv `(c-array uint8 ,actual)) because 1. that would mean there's still another level below (the current %CAST) which would operate on the internal type instead of high-level type descriptions; (defun CAST* (fv type) (%CAST fv (PARSE-C-TYPE type))) ; no! 2. programmers would be able to handle type descriptions like objects, store them, pass them around etc.; 3. and still have guarantees that the amount of run-time parsing is minimised. The same thought applies to FOREIGN-ADDRESS-VARIABLE/FUNCTION and all functions which accept type descriptions. Another approach, maybe to be called "status quo", would be - do not define nor export CAST* etc. + instead, use WITH-FOREIGN-PLACE and its converse C-VAR-OBJECT and have the programmer always operate on places. - concerns about danger of automatic dereferencing still apply. (defun foo (n) (simple-calloc 'uint8 :count n :read-only t)) (setq x (foo 300)) (some-foreign-function x) (defun checksum (fv-object) ; extremely inefficient in CLISP (with-foreign-place (buffer fv-object) (values (loop for i from 0 below (SIZEOF buffer) ;; only works on byte buffers where sizeof = length ;; maybe should use (third (TYPEOF buffer)) sum (ELEMENT buffer i)) (C-VAR-OBJECT (offset memory 0 `(c-array-max character 32)))))) (checksum x) -> 5234 ; #<FOREIGN-VARIABLE of type (c-array-max character 32)> Let's not forget: my article did not mention that operating on foreign places is in CLISP an extremely expensive operation. The above checksum functions runs *several* orders of a magnitude slower than its native code counterpart which one could code using CMUCL, CormanLisp, xyz-Lisp or C. 1. byte-code overhead, not to be avoided in CLISP 2. ELEMENT overhead: for every index position, a new foreign-variable object is created, then thrown away... But with-foreign-place does not help for FOREIGN-ADDRESS-FUNCTION etc., only for ELEMENT, SLOT, CAST, OFFSET. Regards, Jorg Hohle. |