[MLton-devel] Re: finalization in MLton

Stephen Weeks MLton@mlton.org
Mon, 19 May 2003 14:53:36 -0700


> Stephen, your module seems to much more general than mine.  Could you
> send me a sketch of the use-case example you had in mind when you made
> the interface?  (It does not need to be on the list if we are getting
> OT).

The use case for finalizeBefore came from Matthew, and is for when one
wants to keep multiple pointers into a C data structure, e.g. a linked
list, and ensure that internal parts of the data structure aren't
freed to soon.  For the code, see doc/examples/finalizable/.

As I see it, there are two differences between the MLton and MosML
modules:

* The MLton version allows multiple finalizers to be attached, at any
  point in time, while the MosML version attaches a single finalizer
  at creation time.

* The MLton version allows an order to be imposed on finalization.
  The MosML version has no such facility.

The first difference is not a big deal, since each is implementable in
terms of the other, as the following code shows.

------------------------------------------------------------
signature MLTON_FINALIZABLE1 =
   sig
      type 'a t

      val addFinalizer: 'a t * ('a -> unit) -> unit
      val finalizeBefore: 'a t * 'b t -> unit
      val new: 'a -> 'a t
      val withValue: 'a t * ('a -> 'b) -> 'b
   end

signature MLTON_FINALIZABLE2 =
   sig
      type 'a t

      val finalizeBefore: 'a t * 'b t -> unit
      val new: 'a * ('a -> unit) -> 'a t
      val withValue: 'a t * ('a -> 'b) -> 'b
   end

functor F12 (S: MLTON_FINALIZABLE1): MLTON_FINALIZABLE2 =
   struct
      open S

      fun new (x, g) =
	 let
	    val f = S.new x
	    val _ = addFinalizer (f, g)
	 in
	    f
	 end
   end

functor F21 (S: MLTON_FINALIZABLE2): MLTON_FINALIZABLE1 =
   struct
      datatype 'a t = T of {finalizable: 'a S.t,
			    finalizers: ('a -> unit) list ref}

      fun new (x: 'a) =
	 let
	    val r: ('a -> unit) list ref = ref []
	    val f = S.new (x, fn x => List.app (fn f => f x) (!r))
	 in
	    T {finalizable = f,
	       finalizers = r}
	 end

      fun addFinalizer (T {finalizers, ...}, f) =
	 finalizers := f :: !finalizers

      fun finalizeBefore (T {finalizable = f, ...}, T {finalizable = f', ...}) =
	 S.finalizeBefore (f, f')
	 
      fun withValue (T {finalizable = f, ...}, g) =
	 S.withValue (f, g)
   end
------------------------------------------------------------

I'm on the fence as to which of the two approaches should be exported
by MLton.  Arguments either way appreciated.

As to finalizeBefore, again, it can be implemented on top of a more
primitive facility, as the following code shows.

------------------------------------------------------------
signature MLTON_FINALIZABLE0 =
   sig
      type 'a t

      val new: 'a * ('a -> unit) -> 'a t
      val withValue: 'a t * ('a -> 'b) -> 'b
   end

functor F02 (S: MLTON_FINALIZABLE0): MLTON_FINALIZABLE2 =
   struct
      datatype 'a t = T of {afters: (unit -> unit) list ref,
			    finalizable: 'a S.t}

      fun new (x, g) =
	 let
	    val afters = ref []
	 in
	    T {afters = afters,
	       finalizable = S.new (x, fn x =>
				    (g x; List.app (fn h => h ()) (!afters)))}
	 end

      fun finalizeBefore (T {afters, ...}, T {finalizable = f, ...}) =
	 afters := (fn () => S.withValue (f, fn _ => ())) :: !afters

      fun withValue (T {finalizable = f, ...}, g) =
	 S.withValue (f, g)
   end
------------------------------------------------------------

In this case, the code seems tricky enough that it is worth including
finalizeBefore as part of MLton.Finalizable.



-------------------------------------------------------
This SF.net email is sponsored by: ObjectStore.
If flattening out C++ or Java code to make your application fit in a
relational database is painful, don't do it! Check out ObjectStore.
Now part of Progress Software. http://www.objectstore.net/sourceforge
_______________________________________________
MLton-devel mailing list
MLton-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlton-devel