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