[MLton] Registering roots in the FFI
Stephen Weeks
MLton@mlton.org
Mon, 2 May 2005 15:40:02 -0700
> I decided to try the "Register in roots in ML"-approach.
>
> For each type t there are three functions:
>
> registerRoot : t -> int
> getRoot : int -> t
> unregisterRoot : int -> unit
>
> Since there are 17 basic types, and one can have arrays, vectors and
> references of the basic types, and for each combination there are 3
> functions to export. This amounts to 153 functions.
I wonder if it would be better to have a generic Register module,
applicable to any type, instead of a different one for each type.
Something like the following.
--------------------------------------------------------------------------------
signature REGISTER =
sig
structure Type:
sig
type 'a t
val new: unit -> 'a t
end
val get: int * 'a Type.t -> 'a
val register: 'a Type.t * 'a -> int
val unregister: int -> unit
end
structure Register: REGISTER =
struct
type u = exn
structure Type =
struct
datatype 'a t = T of {get: u -> 'a option,
put: 'a -> u}
fun new () =
let
exception E of 'a
in
T {get = fn E a => SOME a | _ => NONE,
put = E}
end
end
val roots: (int * u) list ref = ref []
val next = ref 0
exception NotFound
exception WrongType
fun is i (i', _) = i = i'
fun get (i, Type.T {get, ...}) =
case List.find (is i) (!roots) of
NONE => raise NotFound
| SOME (_, u) =>
case get u of
NONE => raise WrongType
| SOME a => a
fun register (Type.T {put, ...}, a) =
let
val n = !next
val () = roots := (n, put a) :: !roots
val () = next := 1 + n
in
n
end
fun unregister i =
if List.exists (is i) (!roots)
then roots := List.filter (not o (is i)) (!roots)
else raise NotFound
end
--------------------------------------------------------------------------------
Then, you can create "registration types" for all the 51 types you
want to deal with.
> is there a smater way of handling the exporting?
...
> val _ = _export "registerRoot_BoolArray": bool Array.array -> int; BoolArrayRoots.registerRoot;
> val _ = _export "unregisterRoot_BoolArray": int -> unit; BoolArrayRoots.unregisterRoot;
> val _ = _export "getRoot_BoolArray": int -> bool Array.array; BoolArrayRoots.getRoot;
Offhand, I can't think of anything better than this, since the FFI
only supports monotypes, and you want to access all of them. The only
thought I have is to cheat based on the knowledge that a lot of the
types (arrays, vectors, and refs) are pointers. Perhaps those could
be collapsed somehow.