[m-dev.] for discussion: proposed additions to FFI

Jonathan Morgan jonmmorgan at gmail.com
Mon Jun 23 18:05:11 AEST 2008

On Mon, Jun 23, 2008 at 5:12 PM, Julien Fischer
<juliensf at csse.unimelb.edu.au> wrote:
> This proposal extends the FFI with three new pragmas that allow for the
> construction, deconstruction and testing of individual discriminated union
> data constructors in foreign language code.  The runtime already provides a
> mechanism for doing this with the type list/1, e.g. the macros
> MR_list_head(),
> MR_list_tail() and friends (defined in runtime/mercury_tags.h).  It would be
> nice to have something similar for arbitrary d.u. types - writing bindings
> to
> foreign language libraries is the obvious application.
> Unfortunately implementing the above macros by hand is fiddly - the are four
> different implementations in runtime/mercury_tags.h that vary depending upon
> the number of tag bits, number of reserved addresses etc.  So rather than do
> it by hand (which would be quite difficult for non-Mercury developers
> anyway) we
> should get the compiler to do it.
> All of the following can also be done using `pragma foreign_export' but that
> has the disadvantage of being quite expensive, which is unfortunate you need
> to call the exported procedure in the inner loop of a program.  (This
> proposal
> trades the safety of `pragma foreign_export' for improved runtime.)
> An alternative to all of this would be to optimise exported procedures by
> examining their bodies and generating specialised versions of the exported
> procedure in the foreign language that could, for example, avoid saving the
> state of the Mercury VM when that is not necessary.  (My own opinion is that
> we should do both.)
> The proposed three new pragmas are:
>    :- pragma foreign_export_du_construction(<Lang>, <Type>, <Cons>
> <ForeignName>).
>    :- pragma foreign_export_du_deconstruction(<Lang>, <Type>, <Cons>
> <ForeignName>).
>    :- pragma foreign_export_du_test(<Lang>, <Type>, <Cons> <ForeignName>).
> <Lang> is the foreign language.
> <Type> is the name and arity of a Mercury discriminated union  type.
> <Cons> is the name and arity of a data constructor of type <Type>.
> <ForeignName> is the name of a procedure## in language <Lang>.
> ## The meaning of "procedure" depends upon <Lang>.  In C we would
>   almost certainly implement these as macros.
> Some restrictions on them:
> * The pragmas may only occur in the implementation section of a module.
> * The same visibility restrictions with regard to `pragma
> foreign_export_enum'
>  (and its parameters) apply to them (and their parameters).
> * construction/deconstruction foreign_export_du_ pragmas may not be used
> with
>  existentially quantified data constructors.  (There's no real reason for
> this
>  restriction other than using such things would require more detailed
>  knowledge of the Mercury implementation, e.g. type_infos and
>  type_class_infos.)
> * The data passing conventions apply as normal.
> * They may be applied to enumerations although in that case the test and
>  deconstruction operations are identical.
> Examples
> --------
> As an illustration the list operations in the runtime could be implemented
> as:
>    :- pragma foreign_export_du_construction("C", list/1, []/0,
> "MR_list_empty").
>    :- pragma foreign_export_du_test("C", list/1, [], "MR_list_is_empty").
>    :- pragma foreign_export_du_construction("C", list/1, [|]/2,
> "MR_list_cons").
> (This could not be done in practice because doing so would introduce a
> dependency between the standard library and the runtime.)
> Another illustration, this time for the standard library's maybe/0 type:
>    :- pragma foreign_export_du_construction("C", maybe/0, yes/0,
> "ML_maybe_make_yes").
>    :- pragma foreign_export_du_construction("C", maybe/0, no/0,
>  "ML_maybe_make_no").
>    :- pragma foreign_export_du_test("C", maybe/0, no/0, "ML_maybe_is_no").
>    :- pragma foreign_export_du_deconstruction("C", maybe/0,
> "ML_maybe_deconstruct_yes").

I like the idea of the new pragmas, but they raise a few questions in
my mind (especially with the frequent comparisons with

1. Is it possible to automatically generate names, prefixes and so
forth, and then use prefixes and overrides, like foreign_export_enum?
Otherwise most du types will need a lot of foreign declarations to
export them completely, and I imagine most of the time you would want
the export to be either complete or close to it.

2. Does this proposal handle dummy types?  If not, will the
documentation say so?

3. Are there going to be any other attributes governing the pragmas,
like there are for some other foreign pragms?

4. Will the exported procedures be thread-safe?  [this becomes
important when you are using them to write foreign procedures].

5. With the proposed C semantics, will you get similar results from:

if(deconstruct_constructor1(mercury_var, &param1, &param2, &param3))   {
// Do something.
} else if(deconstruct_constructor2(mercury_var, &param1, &param2, &param3))   {
// Do something else.

as from

if(test_is_constructor1(mercury_var)) {
  deconstruct_constructor1(mercury_var, &param1, &param2, &param3)
  // Do something.
} else if(test_is_constructor2(mercury_var)) {
  deconstruct_constructor2(mercury_var, &param1, &param2, &param3)
  // Do something else.

6. Will you ever want to be able to do something like:
switch(get_constructor(mercury_var))  {
    case CONSTRUCTOR1:
    case CONSTRUCTOR2:

I think that the other form, testing for an individual constructor,
will work better, but it could be more lengthy and less possible to
produce a complete switch, and it won't be verified by the compiler
(though if you want that, you might want to do it in Mercury anyway).

mercury-developers mailing list
Post messages to:       mercury-developers at csse.unimelb.edu.au
Administrative Queries: owner-mercury-developers at csse.unimelb.edu.au
Subscriptions:          mercury-developers-request at csse.unimelb.edu.au

More information about the developers mailing list