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 mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by yquem.inria.fr (Postfix) with ESMTP id D06A8BC57 for ; Tue, 6 Jul 2010 00:32:21 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Ai8DALb6MUzRVdQ0kGdsb2JhbACDHJxSCBUBAQEBCQkMBxEDH649O4IMhTouiFMBAQMFgSSDCnIEiDo X-IronPort-AV: E=Sophos;i="4.53,542,1272837600"; d="scan'208";a="62771778" Received: from mail-vw0-f52.google.com ([209.85.212.52]) by mail1-smtp-roc.national.inria.fr with ESMTP; 06 Jul 2010 00:32:21 +0200 Received: by vws11 with SMTP id 11so2797101vws.39 for ; Mon, 05 Jul 2010 15:32:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:mime-version:received:from:date :message-id:subject:to:content-type; bh=VaGXTg3ibeV5gOA5TQceX542JSUPzumhlI0gEMMGOqo=; b=Czyf0VldrHn0StHH9WkwOB2Z0SjcB3JZ2FtKhVsAq1ydkL8m99o1gGbLyFMG85wiZc LiM878R3ohwlgFD8BuraaLKzxVjQxCVLF3FhVTYGWKauO7pBBArgd0bSw6VAlA2GkVWu jVX9z50LNE/QsgCTgCpjYG7UjVrAviw3ui3b0= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:from:date:message-id:subject:to:content-type; b=qpiwktr1FOeobwY/rCxUxgeH14915/O6j54SioJ8oCDd8r4OPuaPj2W1FJQ7PgZ6LA hG5fVqgOYbPKjBd4gQWkGcTE7J4GVButRDNXl7kQtXoTqnhxv5O6vOs9p1GgxFrrqZ6x dVdcELdF6Oz15pkp+V+D8xJkI2OIump1pxRbI= Received: by 10.220.49.204 with SMTP id w12mr1903481vcf.103.1278369140201; Mon, 05 Jul 2010 15:32:20 -0700 (PDT) MIME-Version: 1.0 Received: by 10.220.169.16 with HTTP; Mon, 5 Jul 2010 15:32:00 -0700 (PDT) From: Paolo Donadeo Date: Tue, 6 Jul 2010 00:32:00 +0200 Message-ID: Subject: Binding the Lua library [was: adding a scripting language to an ocaml program] To: OCaml List Content-Type: text/plain; charset=UTF-8 X-Spam: no; 0.00; ocaml:01 ocaml:01 model:01 sandbox:01 mismatch:01 malloc:01 typedef:01 compel:98 cathedral:98 userdata:98 javascript:98 5.1:98 5.1:98 garbage:01 garbage:01 Some time ago I started to write an OCaml binding to the Lua API library [1] and the so called auxiliary library [2]. My objective was a tool to give the user of an application (in this case a web application) the power to extend the application with plugins in a simple and safe environment. I choose Lua because I don't want to compel my user to learn a relatively difficult language like OCaml, nor an esoteric one like Scheme. The user, in the setting I have in mind, is supposed to be strange to programming languages. Moreover Lua is a beautiful language, Scheme inspired, and the model of its development is very similar to OCaml (academic and "cathedral", but open to the community). And Lua has been designed from its start to be an extension language, it's *very* easy to sandbox it. So I wrote the binding to some basic functions and a stress test designed to reveal memory leaks of the binding. The test passed and so I consider the code quite stable, but I had to stop the development due to the chronic lack of time and due to a specific problem: I don't know how to handle the impedance mismatch between the two garbage collectors. Lua has the concept of "userdata": from the C side you can create opaque values (malloc allocated void* objects) along with the operations (C functions conforming a specific typedef) to handle those. It's easy to push the userdatum and its operations on the stack of the Lua state and build an object (a Lua table, similar to a Javascript object). The Lua program can use the object and call methods. This is the way libraries like LuaSocket [3] are written. In an ideal world one want to define an OCaml type, create values of that type and operations on it, push everything on the stack and the use it from the Lua side. But what happen when the Lua GC decide to collect the userdatum? If a "metamethod" __gc is provided (ideally an OCaml function) the Lua state calls it before deallocating the object. But that object could be still alive for the OCaml GC, so what is the standard way (if any) to handle these situations? And again: how to translate (read: how to bind) in OCaml functions like these: void *lua_newuserdata (lua_State *L, size_t size); [4] or void *lua_touserdata (lua_State *L, int index); [5] Is Obj.magic the only possible way? It's ugly and, of course, "Obj.magic is not part of the OCaml language", but in this case you use a cast in C, so why not cast a spell in OCaml? If anyone is interested in my prototype I could clean up the source, remove comments in Italian and publish it on GitHub or OCamlCore. And, of course, any ideas or help on the garbage collector(s) issue are welcome. [1] http://www.lua.org/manual/5.1/manual.html#3 [2] http://www.lua.org/manual/5.1/manual.html#4 [3] http://w3.impa.br/~diego/software/luasocket/ [4] http://www.lua.org/manual/5.1/manual.html#lua_newuserdata [5] http://www.lua.org/manual/5.1/manual.html#lua_touserdata -- Paolo ~ ~ :wq