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