Subject: [clisp-list] critique of default-foreign-language

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Wed Apr 24 03:33:04 2002

Hi,

Sam Steingold wrote:
> I am sorry, but I do not understand a single word of what you are
> saying.

My summary is: the current implementation of default-foreign-language makes simple things look simple, but complex things unpredictably broken.

I'll try the "show by example" approach. Consider:

(DEFAULT-FOREIGN-LANGUAGE :stdc)
(def-call-out foo ...)
(def-call-out bar ...)

(def-c-var callback-pointer (:name "ffi_user_pointer")
  (:type (c-function (:arguments (data c-pointer)) (:return-type int))))

(defun set-callback-1arg (fun)
  ;; symbol-macro on foreign-variable
  (setf callback-pointer fun))

(defun set-callback-2arg (fun)
  (setf (cast callback-pointer
	      '(c-function (:arguments (data c-pointer) (more-data uint)) (:return-type int)))
	fun)

Observations:
a) the programmer gets used not to state :language in foreign function type declarations.

b) CLISP makes no guarantees of any sort as to what gets parsed (-> set in stone) when. I distinguish compile-time, load-time and run-time.

Analysis:
i) callback-1arg works. PARSE-C-TYPE on the callback pointer has been called at load-time, in which the DEFAULT-FOREIGN-LANGUAGE was bound.
ii) callback-2arg can break. It produces different functions, depending on the user's settings or previously loaded or executed code!

This is because PARSE-C-TYPE is called at run-time there, as opposed to load-time (or compilation-time).

One might consider adding :language just in callback-2arg.
I do not like this irregular behaviour at all.
1. How to explain the programmer that the addition
   be needed at just this place and not the others?
2. The programmer might not even add the line, since
   the "set-default-to-stdc" behaviour encourages
   lazyness and incorrect code: s/he might have set it
   earlier (in his/her .mem file) and forget about it.
3. Furthermore, the programmer might not even get a warning for
   this module (and thus never add :language), because other
   code s/he loaded previously may already have set the default.

So my summary is: the current implementation of default-foreign-language makes simple things look simple, but complex things dangerous. That's not what I expect from Lisp.

That's enough for now. I can speak about parse-c-type optimization and also scoping issues at a later time.

Regards,
	Jorg Hohle.

---

From: Sam Steingold <[email-masked]>
Date: Wed Apr 24 08:10:13 2002

> * In message <[email-masked]>
> * On the subject of "[clisp-list] critique of default-foreign-language"
> * Sent on Wed, 24 Apr 2002 12:32:29 +0200
> * Honorable "Hoehle, Joerg-Cyril" <[email-masked]> writes:
>
> My summary is: the current implementation of default-foreign-language
> makes simple things look simple, but complex things unpredictably
> broken.
> 
> b) CLISP makes no guarantees of any sort as to what gets parsed (->
> set in stone) when. I distinguish compile-time, load-time and
> run-time.
> 
> Analysis:

actually, in this particular case, there is no reason not to call
PARSE-C-TYPE at macroexpansion time e.g., 

  (defmacro offset (place offset type &environment env)
    (setq place (macroexpand place env))
    (if (foreign-place-p place 'FOREIGN-VALUE)
      `(FOREIGN-VALUE (%OFFSET ,(second place) ,offset ,(M-PARSE-C-TYPE type)))
      (err `(offset ,place ,offset ,type))))

  (defmacro M-PARSE-C-TYPE (type)
    (if (constantp type) (PARSE-C-TYPE (eval type)) `(PARSE-C-TYPE ,type)))

(or see below).
      
> So my summary is: the current implementation of
> default-foreign-language makes simple things look simple, but complex
> things dangerous. That's not what I expect from Lisp.

I see your point now.
Nevertheless, I do not think that your remedy is any good.
You will just shift the confusion in a different direction: the users
will have to constantly think of using the right call (DEF-C-CALL-OUT or
DEF-STDC-CALL-OUT or DEF-STDC-STDCALL-CALL-OUT &c) or adding the right
:LANGUAGE arguments everywhere.
Another thing is: suppose the library he is interfacing with was
recompiled with a different calling convention.
Then he would have to go over _all_ his code and replace all
DEF-STDC-STDCALL-CALL-OUT with DEF-STDC-CALL-OUT or modify all his
:LANGUAGE arguments.

That's not what I expect from Lisp.

The remedy I would prefer is

1. telling the users that DEFAULT-FOREIGN-LANGUAGE is for compilation
   units and should _never_ be used at top-level (except by gurus :-).

2. moving most type parsing to the macroexpansion time and thus fixing
   your problem with "breaking complex things": if we do
           (defmacro c-function (&whole form) `(parse-c-type ,form))
   similar to
           (defmacro lambda (&whole form) `(function form))
   we will have all constant types parsed at compile time.

3. when the type is non-constant, we should require :LANGUAGE argument
   anyway, whether by using separate forms or requiring it explicitly,
   and I prefer the latter.

Actually, is it possible to extract the calling convention from the
library (foo.so) itself?  Then all this would be much easier.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat7.2 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.palestine-central.com/> <http://www.mideasttruth.com/>
Lottery is a tax on statistics ignorants.  MS is a tax on computer-idiots.