[MLton] Callback to function pointer?

Matthew Fluet fluet@cs.cornell.edu
Thu, 14 Jul 2005 22:49:20 -0400 (EDT)


> > 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?

Agreed.

> > 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.

Fair enough, though I still think that MLton.Pointer is useful for 
direct manipulation of (non-opaque) C objects.  As concise as we try to 
get it, the _XXX primitives still require an annotation and, in the case 
of _symbol, some unpacking to get at the useful bits.

> >   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.

Fair enough.  I added the indirect function calls to support MLNLFFI, so I 
doubt that it has been used all that much.

> 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.

I like making the fetch explicit.

> One could even fold _address in by doing
> 
>    _symbol "symbol": ptrTy, cbTy;       : ptrTy * (unit -> cbTy) * (cbTy -> unit)

I was going to say not to drop _address, because you can also get the
address of a C function symbol (for an indirect function call), for which
the getter/setter are not valid.  OTOH, the main use of indirect function 
calls seem to be calling functions quered for in a dynamic library, so 
there may not be much call for taking the address of a static function to 
make an indirect function call.

> 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.

Is there a better word than "declare"?  If we were to reverse the default, 
then the C attribute "extern" would be appropriate for symbol imported, 
but not declared.  Is there a C attribute for "not-extern"?

> 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)

I like it; I still have a slight preference for including _address.