From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by yquem.inria.fr (Postfix) with ESMTP id 6FD2DBB9C for ; Wed, 23 Nov 2005 13:59:52 +0100 (CET) Received: from pauillac.inria.fr (pauillac.inria.fr [128.93.11.35]) by nez-perce.inria.fr (8.13.0/8.13.0) with ESMTP id jANCxpIS031354 for ; Wed, 23 Nov 2005 13:59:52 +0100 Received: from concorde.inria.fr (concorde.inria.fr [192.93.2.39]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id NAA03359 for ; Wed, 23 Nov 2005 13:59:51 +0100 (MET) Received: from mail.physik.uni-muenchen.de (mail.physik.uni-muenchen.de [192.54.42.129]) by concorde.inria.fr (8.13.0/8.13.0) with ESMTP id jANCxoMK009134 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Wed, 23 Nov 2005 13:59:51 +0100 Received: from localhost (unknown [127.0.0.1]) by mail.physik.uni-muenchen.de (Postfix) with ESMTP id 88E0C20014 for ; Wed, 23 Nov 2005 13:59:50 +0100 (CET) Received: from mail.physik.uni-muenchen.de ([127.0.0.1]) by localhost (mail.physik.uni-muenchen.de [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 07224-01-10 for ; Wed, 23 Nov 2005 13:59:50 +0100 (CET) Received: from mailhost.cip.physik.uni-muenchen.de (kaiser.cip.physik.uni-muenchen.de [141.84.136.1]) by mail.physik.uni-muenchen.de (Postfix) with ESMTP id 5DF6020015 for ; Wed, 23 Nov 2005 13:59:50 +0100 (CET) Received: from eiger.cip.physik.uni-muenchen.de (eiger.cip.physik.uni-muenchen.de [141.84.136.54]) by mailhost.cip.physik.uni-muenchen.de (Postfix) with ESMTP id 53C0726E89 for ; Wed, 23 Nov 2005 13:59:49 +0100 (CET) Received: by eiger.cip.physik.uni-muenchen.de (Postfix, from userid 3092) id A879F34FFF; Wed, 23 Nov 2005 13:59:49 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by eiger.cip.physik.uni-muenchen.de (Postfix) with ESMTP id A031522168 for ; Wed, 23 Nov 2005 13:59:49 +0100 (CET) Date: Wed, 23 Nov 2005 13:59:49 +0100 (CET) From: Thomas Fischbacher To: caml-list@inria.fr Subject: C Callback issues Message-ID: X-BOFH: Daemons did it MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-Virus-Scanned: amavisd-new at physik.uni-muenchen.de X-Miltered: at nez-perce with ID 438467C8.000 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Miltered: at concorde with ID 438467C6.001 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Spam: no; 0.00; foo:01 ocaml:01 ocaml:01 foo:01 associative:01 hash:01 hash:01 limitaion:01 low-level:01 quirks:01 minor:01 shield:98 dictate:98 cip:98 cip:98 X-Spam-Checker-Version: SpamAssassin 3.0.3 (2005-04-27) on yquem.inria.fr X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=disabled version=3.0.3 Hello all, suppose I have a C library which provides functionality via registering C callbacks that take a closure parameter. For the sake of this example, let's say via set_foo_callback(void (*f)(void *),void *closure_param). Now, if I want to lift this to the OCaml level by writing a C callback-wrapper which will use the closure arg to pass the OCaml function to be called, I encounter a slight problem: Callbacks have to be "announced globally" to C by means of Callback.register. Now, if I want to use callbacks not only for internal purposes in my ML wrapper library, but allow the user of that library to set callbacks into his own code, the situation is as follows: Ideally, it would be most convenient if the user could just use the set_foo_callback ML variant of the equally named C function and provide a ML function as callback. This will then be registered on the fly with Callback.register and a gensym-ed name if necessary, and then passed on to the C side. The problem with this is the "if necessary" part. I do not really mind the issue of callback closures becoming non-GC-able, as we will typically only see at most about 100 of them in practically all reasonable programs. However, I definitely want to avoid callback-registering the same closure more than once, as I can imagine situations where the user wants to switch many times between a small set of different callback functions. So, what I need for this approach is a way to find out reasonably fast whether a callback closure has been registered before. One way to do this would be to keep all registered callbacks in an associative list, which is scanned for (==) same-ness whenever a new callback has to be registered. A nicer approach would be to use a hash table, but here we run into the problem that OCaml does not support proper EQ hash tables, and the "workaround" suggested earlier by Xavier does not work with functions. Certainly, if on the C side, caml_name_value() is implemented in such a way (I don't know) that it has to do an O(N) list search instead of a table lookup, there would be no point in trying to improve this by using a hash for the Caml-side lookup. Anyway, I think this is just another indication that there are situations where EQ hash tables really are needed. Right now, I solved this probem in such a way that I split the callback-registering phase off the callback-setting function: I introduced a foo_callback type, which is passed into set_foo_callback, and the user has to use register_foo_callback to map a ML function to a foo_callback. Then it's up to him not to re-register the same function many times as a callback. But somehow, it just does not feel right having to annoy the user of the library with such details, just because of some unrelated obscure OCaml limitaion (no EQ hash tables) that requires that particular kind of design. One may indeed argue that the approach I implemented in the end might be the cleaner one. I somewhat doubt this, as it should eventually become possible to completely shield the end user from low-level details such as that somewhere deep in my ocaml library, it has to register C->Caml callbacks. And as I said, it just does not feel right to have language quirks dictate the design to such an extent. Another minor issue: the documentation of the callbackN function should maybe state more explicitly that the args parameter is of type values[] args, and not a ML vector. (Yes, one may infer this from the presence of the "number of arguments" parameter, which would be spurious if it were a ML vector, but nevertheless.) -- regards, tf@cip.physik.uni-muenchen.de (o_ Thomas Fischbacher - http://www.cip.physik.uni-muenchen.de/~tf //\ (lambda (n) ((lambda (p q r) (p p q r)) (lambda (g x y) V_/_ (if (= x 0) y (g g (- x 1) (* x y)))) n 1)) (Debian GNU)