[MLton] Callback to function pointer?

Stephen Weeks MLton@mlton.org
Thu, 14 Jul 2005 17:59:59 -0700


> I object to using 'a because these primitives stand for a _family_ of
> constants, not polymorphic constants; 

Makes sense.  Certainly for documentation the family should be spelled
out.  For fast-and-lose discussions, it's not so bad :-).

> So, I like the convention of "ptrTy" as a ground type which expands 
> (perhaps opaquely) to a type equivalent to MLton.Pointer.t; 

I think "a type equivalent to" doesn't add anything here.  There isn't
anything (after opaque expansion) equivalent to MLton.Pointer.t other
than itself, right?

> It is not a strict extension, as the current documentation for "_import *"  
> requires it's type annotation to expand to "ptrTy -> (cbTy1 * ... * cbTyn)
> -> cbTy"; that is, the pointer type must be in the annotation.  We should 
> rather have:
> 
>  _import * : ptrTy -> ffiTy;         : ptrTy -> ffiTy;

Good point.

> It also points to a deficency of  "_store *"  which does not specify the 
> elaborated type of the pointer component (preventing it's use with an 
> opaquely annotated "_address").  We should rather have:
> 
>  _store * : ptrTy * cbTy;            : ptrTy * cbTy -> unit;

And another.

> I'll also point out that the MLton.Pointer structure does have an 
> advantage over _store*/_import* in that the MLton.Pointer functions allow 
> for an offset from the base pointer, giving efficient access to C arrays.

An offset could be easily added to _store, _fetch, or whatever we end
up with.

>   Syntax                             | Elaborated type
>  ------------------------------------|---------------------
>  _address "symbol" : ptrTy;          : ptrTy
>  _fetch * : ptrTy -> cbTy;           : ptrTy -> cbTy
>  _fetch "symbol" : cbTy;             : cbTy
>  _store * : ptrTy * cbTy;            : ptrTy * cbTy -> unit
>  _store "symbol": cbTy;              : cbTy -> unit
>  _iccall : ptrTy -> cfTy;            : ptrTy -> cfTy
>  _import "symbol" : cfTy             : cfTy
>  _export "symbol" : cfTy             : cfTy -> unit

I quite like the uniformity of this approach.  I'm willing to lose a
bit on backwards compatibility with "_import *" becoming _iccall,
although it seems a little gratuitous as I don't see a huge benefit.

I wonder if it would be good to push things even further by combining
_fetch and _store, as in:

   _symbol "symbol": cbTy;      : (unit -> cbTy) * (cbTy -> unit)
   _symbol *: ptrTy, cbTy;      : (ptrTy -> cbTy) * (ptrTy * cbTy -> unit)

This also makes when the fetch occurs more explicit.

One could even fold _address in by doing

   _symbol "symbol": ptrTy, cbTy;       : ptrTy * (unit -> cbTy) * (cbTy -> unit)

> And if declaring a C object from ML is truly necessary

I also wonder how necessary this is.  

>  _declare "symbol" : cbTy;           : unit
> 
> or possibly
> 
>  _declare "symbol" : cbTy -> ptrTy;  : ptrTy

How about making declaration an attribute of _symbol?

   _symbol "symbol" declare: ptrTy, cbTy; : ptrTy * (unit -> cbTy) * (cbTy -> unit)

This would declare the symbol but would otherwise behave like _symbol,
giving the address, the getter, and the setter.

Combining everything together, my proposal looks like

_export "symbol" : cfTy                  : cfTy -> unit
_import "symbol" : cfTy                  : cfTy
_import * : ptrTy -> cfTy;               : ptrTy -> cfTy
_symbol "symbol" [declare]: ptrTy, cbTy; : ptrTy * (unit -> cbTy) * (cbTy -> unit)
_symbol *: ptrTy, cbTy;                  : (ptrTy -> cbTy) * (ptrTy * cbTy -> unit)