Hi,
Luis Oliveira wrote:
Glad you were able to fix this issue! You should pass (cffi:null- pointer). CLISP does convert NIL to the null pointer which is unfortunate for this reason (Hi Joerg!) :-) And it seems Lispworks does too.
The lack of uniformity is very unfortunate here. This needs to be fixed. We should either a) translate nil->null everywhere, b) don't translate nil->null anywhere or c) offer the two alternatives through two different types.
Surendra Singhi wrote:
I will vote for clisp's and lispworks approach, it seems least surprising to me. Another related issue is when a C function returns a null pointer. The behavior in that case should be also uniform.
My opinion is: a) the pointer type should be opaque to users. b) Users should be pointed at the problematic string <> NIL <> pointer conversion. That's a requirement for documentation of CFFI/UFFI. c) Use of NIL in CFFI or UFFI is declared non-portable in the documentation. d) CFFI (and UFFI) provide means to pass "pointers" that the foreign side will see as a NULL pointer -- they already do so. e) Such a "pointer" may well be represented as NIL on the Lisp side. Nevertheless its opaque.
f) CFFI and UFFI must export a type for the pointer types they use that is suitable for use with type declarations. -- a TODO for CFFI Example: (deftype pointer #+allegro number(?) #+clisp(or ffi:foreign-address ffi:foreign-variable ffi:foreign-function null)) g) This type cannot be used for discrimination (by this I mean that the CFFI/UFFI documentation specify this property). That is (typep foo 'pointer) does not mean that foo is nothing but a pointer. It could be an integer in Allegro, etc.
h) CFFI does not try to map the implementation's objects into whatever else. Reasons: Meet the user's expectations. Performance. Don't overuse type transforms. i) CFFI exports enough primitives that wrap needed functionality. E.g. POINTER-EQ, IS-NULL-POINTER-P etc.
j) Only acceptable exception to h): Provide a new (non-default) pointer type that does null-pointer-p <-> NIL (or whatever else the user chooses) conversion. Such a thing has its uses. Another useful candidate for post-transforms is the "return-type is mostly unsigned int, except for -1" pattern. E.g. read() and the like. -1 is awful as an unsigned int, and using a signed int when its mostly unsigned also feels wrong.
You will recognize a bias towards "least common denominator", i.e. UFFI-style. However, I'd really dislike CFFI on CLISP back-check every NIL and create a foreign-pointer with address 0 instead :-(
Regards, Jorg Hohle.
On 12/19/05, Hoehle, Joerg-Cyril Joerg-Cyril.Hoehle@t-systems.com wrote:
b) Users should be pointed at the problematic string <> NIL <> pointer conversion. That's a requirement for documentation of CFFI/UFFI. c) Use of NIL in CFFI or UFFI is declared non-portable in the documentation.
[...]
e) Such a "pointer" may well be represented as NIL on the Lisp side. Nevertheless its opaque.
Hmm...
f) CFFI and UFFI must export a type for the pointer types they use that is suitable for use with type declarations. -- a TODO for CFFI Example: (deftype pointer #+allegro number(?) #+clisp(or ffi:foreign-address ffi:foreign-variable ffi:foreign-function null))
I've wondered about this before. This sounds like a good thing to add to the various cffi-sys implementations.
g) This type cannot be used for discrimination (by this I mean that the CFFI/UFFI documentation specify this property). That is (typep foo 'pointer) does not mean that foo is nothing but a pointer. It could be an integer in Allegro, etc.
Allegro does provide an alternative representation for pointers, I guess we should use that unless there's some performance issue.
j) Only acceptable exception to h): Provide a new (non-default) pointer type that does null-pointer-p <-> NIL (or whatever else the user chooses) conversion. Such a thing has its uses. Another useful candidate for post-transforms is the "return-type is mostly unsigned int, except for -1" pattern. E.g. read() and the like. -1 is awful as an unsigned int, and using a signed int when its mostly unsigned also feels wrong.
Let me see if I got this straight, your proposal is that the :pointer type may or may not accept NIL (but it should documented as non-portable), and that we should provide a second pointer type that is guaranteed to translate between the null pointer and NIL.
If this is what you mean, I disagree. I think the behaviour here should be uniform since ideally users would test a set of CFFI bindings on one implementation and be confident that it would work on the other supported lisps.
IMHO, one of biggest drawbacks of UFFI (one that I found while testing uffi-compat on a couple of libs) is the lack of uniformity. For example, in libs primarily developed on lisps with typed pointers (eg: SBCL), many (a few?) operations had bogus types and these bugs didn't show up in these lisps but caused errors on others (and uffi-compat, with whatever lisp).
-- Luís Oliveira http://student.dei.uc.pt/~lmoliv/ Equipa Portuguesa do Translation Project http://www.iro.umontreal.ca/translation/registry.cgi?team=pt
On 12/19/05, Luís Oliveira luismbo@gmail.com wrote:
If this is what you mean, I disagree. I think the behaviour here should be uniform since ideally users would test a set of CFFI bindings on one implementation and be confident that it would work on the other supported lisps.
PMFJI, but as a CFFI user I agree with Luís on this. I personally would still test on each implementation, but non-uniform behavior from CFFI would violate the principle of least surprise because I am expecting CFFI to smooth over differences like this.
-- Jack