[MLton] Callback functions: how?
Wesley W. Terpstra
wesley at terpstra.ca
Wed Feb 14 10:59:57 PST 2007
What's the most efficient way to implement callback functions in MLton?
As I understand it, the code
> val fns : (int -> unit) list ref = ref [ fn _ => () ]
> val register f = fns := f :: !fns
> val runAll x = List.app (fn f => f x) (!fns)
will prevent flow-analysis and the runAll method will have a loop
over a giant switch statement that could call all possible functions
of type 'int -> unit'. Is this correct? Or can MLton recognize that
only methods passed to 'register' need to be in the switch statement?
I'm trying to wrap the standard C idiom of 'void registercb(const
char* name, void (*cb)(void* uarg, ...), void* uarg);'. My best idea
so far is to use the 'uarg' as a word that is the index into some SML-
side vector of callback functions. eg:
> local
> val fns = GrowingVector.empty
> fun runOne (id, x) = GrowingVector.sub (fns, Word.toInt id) x
> val () = _export "mlton_lib_ufnhook": (word * ... -> unit) ->
> unit; runOne
> val runOne_addr = _address "mlton_lib_ufnhook" : MLton.Pointer.t;
> val Cregistercb = _import "registercb" : string * MLton.Pointer.t
> * word -> unit;
> in
> fun registercb (name, f) = registercb (name, runOne_addr,
> Word.fromInt (GrowingVector.insert f))
> end
Is there a better way? Can MLton (still) recognize that only
registercb'd methods need be in the switch?
This idiom appears in enough C libraries that we should really have a
good solution for this in the FFI section of the wiki. If a good
solution is relatively complex, perhaps we should offer a small
library (I'l volunteer to write it). For my scenario, it's quite
important that this be as fast as possible---callbacks are invoked
inside a tight loop, and the callbacks themselves are very simple.
Also, what's the best known way to implement GrowingVector? I've been
using
> datatype 'a used = FREE of int | USED of 'a
> type 'a t = { free: int, buf: 'a used array }
where buf doubles in size when free = ~1. This isn't such a big deal,
since 'registercb' is rarely invoked compared to 'runOne'. However,
I'd like to know a better solution.
|'m assuming Henry has a good solution to this in his secret mGtk/
MLton port. Of course, it's not in svn, so I can't look and see...
More information about the MLton
mailing list