[MLton] adding synchronous finalizers
Stephen Weeks
MLton@mlton.org
Fri, 1 Oct 2004 13:12:59 -0700
> I'm ok for now with only finalizers being handled. Probably the Gtk
> people should speak up if it is a problem for their use.
We're not taking any functionality away, so it shouldn't hurt.
Although it would be nice to know if this is the kind of synchronous
behavior they want. Henning Niss is on the list, but I don't know how
closely he follows -- Henning, are you reading this?
> >From my understanding of your code (and my knowledge of the MLton
> run-time system is VERY weak with regards to any of the
> multi-threaded stuff), won't it pay attention to the flag only when
> an object is added to the finalization world? That certainly isn't
> what I would have expected: I would think that setting
> Finalizable.finalizeSynchronously to true would mean that no
> finalizers would be called (except via Finalizable.runFinalizers)
> until I set it to false. Also, when I set it to false I would
> expect all finalizers, even ones made finalizable while it was true,
> to then run automatically.
You're right. And I like your proposed behavior better. This kind of
difference is one argument for making finalizeSynchnronously a
compile-time constant -- in that case our proposals are identical. In
any case, here's an attempt at a patch for your semantics.
----------------------------------------------------------------------
structure Finalizable:
sig
include MLTON_FINALIZABLE
val runFinalizers: unit -> unit
val setRunSynchronously: bool -> unit
end =
struct
structure F = MLton.Finalizable
open F
val synchronously: bool ref = ref false
val finalizers: (unit -> unit) list ref = ref []
fun addFinalizer (v, f) =
F.addFinalizer
(v, fn a =>
if !synchronously
then finalizers := (fn () => f a) :: !finalizers
else f a)
fun runFinalizers () =
List.app (fn f => f ())
(MLton.Thread.atomically
(fn () => !finalizers before (finalizers := [])))
fun setRunSynchronously b =
if b = !synchronously
then ()
else (synchronously := b
; if b
then ()
else runFinalizers ())
end
----------------------------------------------------------------------
Another possible behavior would be to report an error if the client
does setRunSynchronously false and there are pending finalizers.
Given the messiness with changing the synchronousness, maybe it
would be better to go with a compile-time constant.
> I think that it is important to realize that there are two distinct reasons
> (well, at least two) for including things in MLton instead of having people
> implement them themselves: one is that you can't implement it unless you go
> into the run-time system. Another one, and I think the one that is important
> here, is when it is important that all uses of a facility use it in a
> compatible way. I.e., if I want to run some code with only synchronus
> finalization, I want that to be the case even for finalization of objects
> that I have nothing to do with creating. That seems to require a program-
> wide agreement, and so argues strongly to put it in MLton.Finalizable
Good point.