[MLton] Callback to function pointer?
Wesley W. Terpstra
Tue, 12 Jul 2005 21:05:36 +0200
(Sorry about not CC'ing the first time, I see I messed you up too ;-)
On Tue, Jul 12, 2005 at 11:15:39AM -0400, Matthew Fluet wrote:
> So, things to clear up. First, the "_export" expression has both a static
> component and a dynamic component. To implement exported SML functions,
> the compiler creates an array of entry points (essentially, unit -> unit
> functions that take care of wrapping the real SML function with fetches
> and stores of the C arguments and results). Each (static) "_export" in
> the source maps to one element of the array. When C calls an "_export"ed
> function, it really calls a stub that sets up the C arguments and then
> dispatches in to the MLton runtime with a unique integer indicating which
> entry in the array to call.
> The dynamic component of an "_export" expression updates the array of
> entry points with the SML function passed to "_export".
> Hence, it is inadvisable to evaluate the same static "_export" with
> different SML functions, since, as you observed, the last SML function
> wins. Also, it is inadvisable to call an "_export"ed function from C
> before the "_export" expression is evaluated in SML, since no SML function
> will have been registered.
> Taken together, it is really best to only have "_export" in top-level
> declarations -- hence, they will be evaluated exactly once and before
> useful SML code evaluates.
Yeah, this all makes perfect sense, and is more or less how I thought
things worked. I had hoped to be able to wrap methods that accept
function pointers with SML functions which take SML functions.
ie: gui_clicked <your-event-handler-here>
where you can pass in different methods 'on the fly'.
I guess I will have to stick to exporting one global function which uses a
lookup table to locate the correct method to invoke. This is what mgtk does
too... I had just hoped to keep things tighter.
> fun clicker1 () = print "clicked callback 1!\n"
> val () = (_export "clicker1" : unit -> unit;) clicker1
> val clicker1Ptr = _import # "clicker1": MLton.Pointer.t
That is a useful hack!
That import2.sml uses a couple features I didn't know about---great! =)
> Admittedly, a little more verbose that what you originally wrote, though
> not too bad. I could imagine allowing:
> _export # "name" : (tyArg -> tyRes) -> tyPtr;
Probably not worth it; if a person is using the FFI, he deserves a little
pain to encourage him to keep his interface clean. ;-)
Wesley W. Terpstra