[m-dev.] for discussion: foreign_export_enum syntax

Jonathan Morgan jonmmorgan at gmail.com
Mon Jul 2 21:14:37 AEST 2007


On 7/2/07, Julien Fischer <juliensf at csse.unimelb.edu.au> wrote:
>
> On Mon, 2 Jul 2007, Jonathan Morgan wrote:
>
> > On 6/27/07, Julien Fischer <juliensf at csse.unimelb.edu.au> wrote:
> >> I have been working on the change to allow Mercury enumeration constants
> >> to be exported to foreign languages.  The majority of the changes to
> >> the compiler were made last year; what remains undecided is the
> >> concrete syntax.  Below is change to the reference manual that describes
> >> the current version of this new feature.  Here is a small example of
> >> how it would look and work in the case where C is the foreign language.
> >
> > I've been considering bringing this up again in the last couple of
> > weeks, so you've saved me the trouble of doing that.
>
> Glad to be of help!
>
> >> Example
> >> -------
> >>
> >> :- type foo
> >>                 --->    foo
> >>                 ;               bar
> >>                 ;               baz.
> >>
> >>         :- pragma foreign_export_enum("C", foo, [bar - "BAR],
> >>                 [prefix("MR_"]).
> >>
> >> would cause the following declaration to be generated in the .mh file.
> >>
> >>         enum {
> >>                         MR_foo = 0,
> >>                         MR_BAR = 1,
> >>                         MR_baz = 2
> >>         };
> >
> > Is there any particular reason for choosing enums over #define's?
>
> Not particularly.
>
> > I would expect #define's to be a better option as they do not specify
> > any type for the resultant constant, whereas an enum specifies an enum
> > type for the constant, which is probably different from the standard
> > Mercury type (MR_Word?).
>
> Identifiers used as enumeration constants in C have type int.
>
> > While this may not be a problem with C's
> > weak type system, it could potentially cause problems with C++ or
> > C/C++ compilers (are there any plans to support a C++ compiler with
> > any of the high-level C grades?).
>
> Not in the immediate future (see comments in mlds_to_c.m if you are
> interested in a C++ backend), but since we want the code the in the .mh
> files to be compatible with C++ for the purposes of interoperability, we
> should probably use #defines.
>
> >> +For each foreign language there is a default mapping between the name
> >> +of a Mercury constructor and its symbolic name in the language @var{Lang}.
> >> +This default mapping is not required to map every valid constructor name
> >> +to a valid name in language @var{Lang}; where it does not the programmer
> >> +must specify a valid symbolic name.
> >> +The programmer may also choose to map a constructor to a symbolic name
> >> +that differs from the one supplied by the default mapping for language
> >> + at var{Lang}.
> >> + at var{Overrides} is a list of pairs of constructor names and strings of
> >> +the following form:
> >> +
> >> + at example
> >> +[consI - "symbolI", ..., consJ - "symbolJ"]
> >> + at end example
> >> +
> >> +This can be used to provide either a valid symbolic name where the
> >> +default mapping does not, or to override a valid symbolic name
> >> +generated by the default mapping.
> >
> > Do you have to specify an empty list if there are no renamings? i
>
> No, you should be able to omit it in that case; unless you have attributes.
> (That might seem confusing but it's the same thing we do with mutable
> declarations; maybe it would be better to swap the position of those two
> arguments?)

It depends on which one is more likely.  I suspect that (with a
reasonable choice of default name and a use of prefixes) very few
overrides will be necessary, while most users will use prefixes, so
switching the order would probably work well.

> > (I can imagine that requirement being potentially confusing if most uses
> > of the pragma didn't do any renaming).  An alternative (for if renaming
> > was scarce) would be to make each renaming a separate attribute (e.g.
> > rename(x, "X")), though I don't think that it would really help.
>
> Another choice, would be to make overrides into an attribute and have
> something like:
>
>         :- pragma foreign_export_enum("C",
>                 foo,
>                 [
>                         prefix("MR_"),
>                         overrides([foo - "FOO", bar - "BAR"])
>                 ]).
>
> I'm not so keen on that one, but I guess I could live with it.

I'm not keen on either of them, but they would make your intentions
more explicit if you only rename some constructors.

...
> > I've also been considering an implementation for foreign_import_enum,
> > if we were to have such a thing.
>
> This has come up several times before (every time foreign_export_enum
> has been discussed in fact) - I've never really seen a proposal for
> it that I have been entirely satisfied with.

Neither have I, though it is a thing that would be nice to have.

> > I assume that it would look
> > something like:
> >
> > :- pragma foreign_import_enum("C", my_enum, "MyEnum", [a -
> > "MY_ENUM_A", b - "MY_ENUM_B"]).
> >
> > [something of a cross between a foreign type declaration and a type
> > constructor declaration].
> >
> > and I've come up with the following couple of ideas:
> >
> > 1. Represent the imported type as a foreign type, and provide
> > functions to access the valid constants.
> >
> > 2. Create a new Mercury type for the imported type, and marshal
> > between the Mercury type and the foreign type whenever going into or
> > out of a foreign code layer (e.g. at foreign_proc and foreign_export
> > boundaries).
>
> What about foreign_procs or foreign_exports with polymorphic arguments?
> How is the compiler to decide whether to call the marshalling code?

Didn't occur to me.  Probably it shouldn't marshal it, but that
doesn't leave it clear to me where the marshalling should be done with
polymorphic types (if anywhere).

Just FYI, this second approach is what I use with Gtk+, and it ends up
fairly cumbersome (though it isn't a problem when it is automatically
generated).

> > While neither of these ideas are necessarily perfect, they each offer
> > different trade-offs.  The first option is fairly efficient (no
> > marshalling costs), but potentially requires a function call for
> > creating any value in Mercury.
>
> Compiling with --intermodule-optimization enabled should result in most
> of those functions being inlined though.  (Some of the library bindings
> in extras do things this way.)

I know: that's where I got the idea from.

> > The second option allows switching on the type in Mercury code, but
> > requires conversions on every foreign language call.  Neither option
> > supports overlapping enumeration values very well (which happens in quite
> > a few libraries).
> >
> > A potential problem with this declaration as is is that it doesn't
> > support a good distinction between whether the constructors for the
> > type are public or private.  With an ordinary type declaration, this
> > would be determined by whether the type definition was in the
> > interface section or the implementation section, but it is not usual
> > to put foreign declarations of this sort in Mercury interfaces (as
> > they expose implementation details).  Also, the constants used in the
> > definition will need to be accessible to the generated code (probably
> > through foreign_decl clauses).
>
> And it's a little bit tricker than that if the things in foreign constants
> foreign_import_enum pragma are #defines, since we then need to make sure
> that the appropriate #include is available to an importing module.
> (For library bindings if you do not allow the constants to be #defines
> then I think this particular feature loses a lot of its appeal.)

Would not a `foreign_decl' including the relevant header file or
declaring the relevant types be sufficient?

> Thanks for the feedback!

No problems.  It's a thing that I am likely to use.

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