[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.