From: Jeff M.
Subject: Lisp-ifying FFI's
Date: 
Message-ID: <1114723980.054734.142840@z14g2000cwz.googlegroups.com>
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.

From: Kenny Tilton
Subject: Re: Lisp-ifying FFI's
Date: 
Message-ID: <9%cce.16792$mp6.2481618@twister.nyc.rr.com>
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
From: Duane Rettig
Subject: Re: Lisp-ifying FFI's
Date: 
Message-ID: <4ll72a2ff.fsf@franz.com>
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   
From: Kenny Tilton
Subject: Re: Lisp-ifying FFI's
Date: 
Message-ID: <6Tfce.16797$mp6.2501765@twister.nyc.rr.com>
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
From: David Steuber
Subject: Re: Lisp-ifying FFI's
Date: 
Message-ID: <87acnglpup.fsf@david-steuber.com>
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
From: Pascal Bourguignon
Subject: Re: Lisp-ifying FFI's
Date: 
Message-ID: <87acnijs5z.fsf@thalassa.informatimago.com>
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
From: Thomas Gagne
Subject: Re: Lisp-ifying FFI's
Date: 
Message-ID: <I5GdnVx8dbe5fevfRVn-rw@wideopenwest.com>
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.