[MLton] Callback to function pointer?

Wesley W. Terpstra wesley@terpstra.ca
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