I was wondering what the general practice is for Lisp-ifying foreign
interfaces. For example, if I had a dynamic library with the following
function:
bool is_power_of_2(int n);
Is it considered good practice to keep this function name the same? or
to rename it to one of the following in the FFI:
'is_power_of_2' or 'is-power-of-2' or 'power-of-2-p'
Normally I wouldn't care (and I'd use the 'power-of-2-p' choice), but
I'm actually putting something together that others might feel useful,
and I'd like to stick with common convention.
Best wishes,
Jeff M.
Jeff M. wrote:
> I was wondering what the general practice is for Lisp-ifying foreign
> interfaces. For example, if I had a dynamic library with the following
> function:
>
> bool is_power_of_2(int n);
>
> Is it considered good practice to keep this function name the same? or
> to rename it to one of the following in the FFI:
>
> 'is_power_of_2' or 'is-power-of-2' or 'power-of-2-p'
The Savages of C.L.L. definitely will fall down foaming at the mouth if
you stick with underscores or camelCase, but I do not know how they feel
about actually changing the text from is- to -p. I wager they will not
go for the text change.
kt
--
Cells? Cello? Cells-Gtk?: http://www.common-lisp.net/project/cells/
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"Doctor, I wrestled with reality for forty years, and I am happy to
state that I finally won out over it." -- Elwood P. Dowd
Kenny Tilton <·······@nyc.rr.com> writes:
> Jeff M. wrote:
> > I was wondering what the general practice is for Lisp-ifying foreign
> > interfaces. For example, if I had a dynamic library with the following
> > function:
> > bool is_power_of_2(int n);
>
> > Is it considered good practice to keep this function name the same?
> > or
>
> > to rename it to one of the following in the FFI:
> > 'is_power_of_2' or 'is-power-of-2' or 'power-of-2-p'
>
>
> The Savages of C.L.L. definitely will fall down foaming at the mouth
> if you stick with underscores or camelCase, but I do not know how they
> feel about actually changing the text from is- to -p. I wager they
> will not go for the text change.
Why not? A foreign interface is just that; an interface to foreign
code. And just as the bool declaration must be converted from 0/non-0
to nil/non-nil (hopefully automatically), names are good candidates
for lispifying as well. Note that I'm not advocating for this style
exclusively, but I advocate for the availability of the choice.
That's Common Lisp: choices, choices.
In Allegro CL's FFI, the above definition might be
(ff:def-foreign-call (power-of-2-p "is_power_of_2") (n)
:returning boolean)
I'm sure other FFIs have similar capabilities.
--
Duane Rettig ·····@franz.com Franz Inc. http://www.franz.com/
555 12th St., Suite 1450 http://www.555citycenter.com/
Oakland, Ca. 94607 Phone: (510) 452-2000; Fax: (510) 452-0182
Duane Rettig wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
>
>
>>Jeff M. wrote:
>>
>>>I was wondering what the general practice is for Lisp-ifying foreign
>>>interfaces. For example, if I had a dynamic library with the following
>>>function:
>>>bool is_power_of_2(int n);
>>
>>>Is it considered good practice to keep this function name the same?
>>>or
>>
>>>to rename it to one of the following in the FFI:
>>>'is_power_of_2' or 'is-power-of-2' or 'power-of-2-p'
>>
>>
>>The Savages of C.L.L. definitely will fall down foaming at the mouth
>>if you stick with underscores or camelCase, but I do not know how they
>>feel about actually changing the text from is- to -p. I wager they
>>will not go for the text change.
>
>
> Why not? A foreign interface is just that; an interface to foreign
> code.
Yes, and god forbid someone be able to use the name of the lisp function
to find the documentation of the foreign function. I feel free now to go
ahead and wrap OpenGL's gluCylinder with the lisp draw-a-pretty-tube,
something I have wanted to do for a while. It is vastly more important
that the sacred ground of Lisp code not be sullied by names not
conforming to goofy conventions like -p.
:)
kenny
ps. Loved seeing a macro in a recent ACL7 backtrace. Your work? I
remember you mentioning that over lunch at ILC 2002 or so. k
--
Cells? Cello? Cells-Gtk?: http://www.common-lisp.net/project/cells/
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"Doctor, I wrestled with reality for forty years, and I am happy to
state that I finally won out over it." -- Elwood P. Dowd
Kenny Tilton <·······@nyc.rr.com> writes:
> Duane Rettig wrote:
>
> > Kenny Tilton <·······@nyc.rr.com> writes:
> >
> >>Jeff M. wrote:
> >>
> >>>I was wondering what the general practice is for Lisp-ifying foreign
> >>>interfaces. For example, if I had a dynamic library with the following
> >>>function:
> >>>bool is_power_of_2(int n);
> >>
> >>> Is it considered good practice to keep this function name the
> >>> same? or to rename it to one of the following in the FFI:
> >>>'is_power_of_2' or 'is-power-of-2' or 'power-of-2-p'
> >>
> >>The Savages of C.L.L. definitely will fall down foaming at the mouth
> >>if you stick with underscores or camelCase, but I do not know how they
> >>feel about actually changing the text from is- to -p. I wager they
> >>will not go for the text change.
> > Why not? A foreign interface is just that; an interface to foreign
> > code.
>
> Yes, and god forbid someone be able to use the name of the lisp
> function to find the documentation of the foreign function. I feel
> free now to go ahead and wrap OpenGL's gluCylinder with the lisp
> draw-a-pretty-tube, something I have wanted to do for a while. It is
> vastly more important that the sacred ground of Lisp code not be
> sullied by names not conforming to goofy conventions like -p.
For creating OpenGL bindings, I used a lispify-name function defined
like this:
(defun lispify-name (name &optional (package-name ""))
(let
((tn (trim-string-prefix "-"
(trim-string-prefix (string-upcase (string package-name))
(with-output-to-string (s)
(loop with last-lower = (lower-case-p (char name 0))
for c across name
do (case c
(#\_ (princ #\- s) (setf last-lower nil))
(otherwise (when (and (shiftf last-lower (lower-case-p c))
(not last-lower))
(princ #\- s))
(princ (char-upcase c) s)))))))))
(setf (gethash name *translated-names*) (list tn (string package-name)))
tn))
It's not perfect of course. One thing that was annoying was what
happened to the function glRotatef(). My algorithm turned it into
rotatef in the gl package. Fortunately the gl package did not need to
use common-lisp.
--
An ideal world is left as an excercise to the reader.
--- Paul Graham, On Lisp 8.1
No excuses. No apologies. Just do it.
--- Erik Naggum
Kenny Tilton <·······@nyc.rr.com> writes:
> Jeff M. wrote:
>> I was wondering what the general practice is for Lisp-ifying foreign
>> interfaces. For example, if I had a dynamic library with the following
>> function:
>> bool is_power_of_2(int n);
>> Is it considered good practice to keep this function name the same?
>> or
>> to rename it to one of the following in the FFI:
>> 'is_power_of_2' or 'is-power-of-2' or 'power-of-2-p'
>
> The Savages of C.L.L. definitely will fall down foaming at the mouth
> if you stick with underscores or camelCase, but I do not know how they
> feel about actually changing the text from is- to -p. I wager they
> will not go for the text change.
I'd say, if the source names are systemically constructed, one can
easily formally specify the lispification.
On the other hand, if the source names are ad-hoc, then it's
harder. We can still lispify them but the resulting names may not be
so good, and it might be better to use a dictionary. For example,
POSIX names.
Now, for is_predicate to PREDICATEP or is_really_predicate to
REALLY-PREDICATE-P, I note that in some API, systematically we have
also names such as: are_predicate, has_predicate, will_predicate,
did_predicate (eg. OpenStep "willCloseWindow" "didCloseWindow", etc).
The -P convention is not rich enough to express all these nuances. So
if the API use them it might be better to leave them.
Moreover, note how some -P functions in COMMON-LISP are misleading:
DIGIT-CHAR-P doesn't return only a boolean (it's not a mere
predicate), but also returns a useful number which is the value of
the digit. I would not have named DIGIT-CHAR-P...
;;****************************************************************************
;;FILE: lispify.lisp
;;LANGUAGE: Common-Lisp
;;SYSTEM: Common-Lisp
;;USER-INTERFACE: NONE
;;DESCRIPTION
;;
;; A function to lispify FFI names.
;;
;;AUTHORS
;; <PJB> Pascal Bourguignon <···@informatimago.com>
;;MODIFICATIONS
;; 2005-04-29 <PJB> Created.
;;BUGS
;;LEGAL
;; GPL
;;
;; Copyright Pascal Bourguignon 2005 - 2005
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version
;; 2 of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be
;; useful, but WITHOUT ANY WARRANTY; without even the implied
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;; PURPOSE. See the GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public
;; License along with this program; if not, write to the Free
;; Software Foundation, Inc., 59 Temple Place, Suite 330,
;; Boston, MA 02111-1307 USA
;;****************************************************************************
(DEFMACRO WITH-GENSYMS (SYMS &BODY BODY)
"
DO: Replaces given symbols with gensyms. Useful for creating macros.
NOTE: This version by Paul Graham in On Lisp."
`(LET ,(MAPCAR (LAMBDA (S) `(,S (GENSYM (string ',S)))) SYMS) ,@BODY))
(defmacro wsiosbp (&body body)
(let ((vpack (gensym)))
`(let ((,vpack *package*))
(with-standard-io-syntax
(let ((*package* ,vpack))
,@body)))))
(defmacro state-automata (variables &rest transitions)
(with-gensyms (errtag curstate)
`(let ((,curstate nil) ,@variables)
(macrolet ((transition (guard action state)
`(when ,guard ,action (go ,state)))
(state () ',curstate))
(block nil
(tagbody
,@(mapcan (lambda (trans)
(if (listp (car trans))
(append (car trans)
`(setf ,curstate ',(car trans))
`((progn ,@(cdr trans)))
`(go ,errtag))
(list (car trans)
`(setf ,curstate ',(car trans))
`(progn ,@(cdr trans))
`(go ,errtag))))
transitions)
,errtag (error "No transition from state ~A" ,curstate)))))))
(defun lispify (name)
"RETURN: Lispified name."
(setf name (string name))
(format
nil ···@(~{~A~^-~}~)"
(macrolet
((collect-word
(&optional (epsilon 0) (delta 0))
`(progn
(push (subseq name start (+ i ,epsilon)) words)
(setf start (+ i ,delta))
(incf i)))
(collect-empty () `(progn (push "" words) (incf i) (setf start i)))
(end-of-name () `(>= i (length name)))
(upper-case () `(upper-case-p (aref name i)))
(under-line () `(char= (character "_") (aref name i)))
(trace () `(format t "~10A: ~4D ~4D ~A<~A>~A ~S~%"
(state) start i
(subseq name 0 start)
(subseq name start i)
(subseq name i) words)))
(state-automata ((words '())
(start 0)
(i 0))
(:init
;; (trace)
(transition (end-of-name) nil :terminate)
(transition (under-line) (collect-empty) :init)
(transition (upper-case) (incf i) :upper1)
(transition t (incf i) :lower))
(:lower
;; (trace)
(transition (end-of-name) nil :terminate)
(transition (under-line) (collect-word 0 1) :init)
(transition (upper-case) (collect-word) :upper1)
(transition t (incf i) :lower))
(:upper1
;; (trace)
(transition (end-of-name) nil :terminate)
(transition (under-line) (collect-word 0 1) :init)
(transition (upper-case) (incf i) :upper2)
(transition t (incf i) :lower))
(:upper2
;; (trace)
(transition (end-of-name) nil :terminate)
(transition (under-line) (collect-word 0 1) :init)
(transition (upper-case) (incf i) :upper2)
(transition t (collect-word -1 -1) :lower))
(:terminate
(when (< start i)
(push (subseq name start i) words))
;; (trace)
(return (nreverse words)))))))
(DEFUN PREFIX-P (STRING PREFIX)
"
RETURN: Whether PREFIX is a prefix of the STRING.
"
(AND (<= (LENGTH PREFIX) (LENGTH STRING))
(STRING= STRING PREFIX :END1 (LENGTH PREFIX))));;PREFIX-P
(defun lispify-more (name)
(let ((lame (lispify name)))
(when (prefix-p lame "IS-")
(setf lame (format nil "~A-P" (subseq lame 3))))
;; ...
lame))
(defun test()
(dolist (test '(("Count_Perl" "COUNT-PERL")
("universe__big_bang" "UNIVERSE--BIG-BANG")
("universe_Big_BANG" "UNIVERSE-BIG-BANG")
("universe__BIG_BANG" "UNIVERSE--BIG-BANG")
("universe__Big_Bang" "UNIVERSE--BIG-BANG")
("NSWindowState" "NS-WINDOW-STATE")
("BUFSIZE" "BUFSIZE")
("UPPERcase" "UPPE-RCASE") ; !!!
("is_predicate" "IS-PREDICATE" "PREDICATE-P")
("are_predicate" "ARE-PREDICATE") ; What?
("has_predicate" "HAS-PREDICATE")
("will_predicate" "WILL-PREDICATE")
("had_predicate" "HAD-PREDICATE")
))
(assert (string= (lispify (first test)) (second test))
(test) "Test failed: (LISPIFY ~S) --> ~S instead of ~S"
(first test) (lispify (first test)) (second test))
(when (= 3 (length test))
(assert (string= (lispify-more (first test)) (third test))
(test) "Test failed: (LISPIFY-MORE ~S) --> ~S instead of ~S"
(first test) (lispify-more (first test)) (third test))))
:success)
;; (wsiosbp (intern (lispify c-name)))
;; Local Variable:
;; eval: (cl-indent 'state-automata 1)
;; End:
--
__Pascal Bourguignon__ http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush
I'm unsure of Lisp's idioms, but I've done multiple of these for
Smalltalk and the answer is there is, both.
I create one interface which maps mostly one-to-one with the foreign
language function, then wrap it with another protocol to make it more
Smalltalk-ish.
Soon, I hope, I'll be creating a Lisp interface to the middleware
libraries for isectd and will likely do something similar.