[mercury-users] Working with exported types

Jonathan Morgan jonmmorgan at gmail.com
Thu Jul 27 17:02:17 AEST 2006


On 7/27/06, Julien Fischer <juliensf at csse.unimelb.edu.au> wrote:
>
> On Thu, 27 Jul 2006, Jonathan Morgan wrote:
>
> > Say I have an enum something like the following.
> >
> > :- type my_enum --->
> >   value1 ;
> >   value2 ;
> >   value3.
> >
> > If I am working with such a type in foreign code there are a couple of
> > ways I could do it.
> >
> > 1. Assume that value1, value2 and value3 map to the values 0, 1 and 2,
> > and then just test against or assign these values.  Efficient, but may
> > be broken by change in representation.
>
> At the moment the only thing that is likely to break this representation
> is using the .rt grades (and they're deprecated anyhow).  (Actually,
> I changing the current representation of enums will break the standard
> library.)
>
> > 2. Export Mercury predicates that work on this type, and use these
> > exported predicate exclusively.
> >
> > For example:
> >
> > :- pragma export(my_enum_is_value1(in), "module_my_enum_is_value1").
> > :- pred my_enum_is_value1(my_enum::in) is semidet.
> > my_enum_is_value1(value1).
> >
> > :- pragma export(my_enum_is_value2(in), "module_my_enum_is_value2").
> > :- pred my_enum_is_value2(my_enum::in) is semidet.
> > my_enum_is_value2(value2).
> >
> > :- pragma export(my_enum_is_value3(in), "module_my_enum_is_value3").
> > :- pred my_enum_is_value3(my_enum::in) is semidet.
> > my_enum_is_value3(value3).
> >
> > :- pragma export(my_enum_value1 = out, "module_my_enum_value1").
> > :- func my_enum_value1 = my_enum.
> > my_enum_value1 = value1.
> >
> > :- pragma export(my_enum_value2 = out, "module_my_enum_value2").
> > :- func my_enum_value2 = my_enum.
> > my_enum_value2 = value2.
> >
> > :- pragma export(my_enum_value3 = out, "module_my_enum_value3").
> > :- func my_enum_value3 = my_enum.
> > my_enum_value3 = value3.
> >
> > This second way will not break if the representation changes, but is
> > very cumbersome to use.  Interestingly, mtcltk uses both of these
> > methods when dealing with tcl_status - when writing to a variable it
> > uses method one, but when reading from it it uses method two.
> >
> > Which of these methods is likely to be better?
>
> The second one is very heavyweight.  Setting up calls back to Mercury adds
> all sorts of code for setting up and saving the state of the Mercury engine.
>
> A third alternative is the one used by the OpenGL binding.  Add a function
> that maps the Mercury enums onto integers and pass the integers to C.
>
> Another approach that I have thought about adding (because doing the above
> in the OpenGL binding was fairly tedious), is to add a foreign_enum pragma
> that would allow you to safely use the values of Mercury enums on the other
> side of the foreign language interface, something like:
>
>         :- type foo
>                 --->    foo
>                 ;       bar
>                 ;       baz
>
>         :- pragma foreign_enum("C", [
>                 foo - "FOO",
>                 bar - "BAR",
>                 baz - "BAZ"]).
>
> The compiler would then add the following to the modules .mh file:
>
>         #define FOO <representation of foo>
>         #define BAR <representation of bar>
>         #define BAZ (representation of baz>

Interesting idea.  I have considered a more general export that would
use functions and deal with any user-defined types.  For something
like the following:

:- type my_type --->
    type1(int, int) ;
    type2(char, int) ;
    type3(char, string).

I think that the only reasonable way of accessing it is using accessor
functions like:

:- pred my_type_is_type1(my_type :: in, int :: out, int :: out) is semidet.
my_type_is_type1(type1(X, Y), X, Y).

:- func my_type_type1(int, int) = type1.
my_type_type1(X, Y) = type1(X,Y).

Again, this gets verbose, but something more general than foreign_enum
would be required if you wished to avoid doing it manually.  The
export would probably have to either have to name all the functions
(getters and setters), or just name the type.

I would prefer to just name the type, so that pragma
export_type(my_type, "module_my_type") would give me, for each
constructor, something like module_my_type_[constructor], which takes
a set of parameters and constructs the type, and
module_my_type_is_[constructor], which has a set of out parameters to
deconstruct the type.  However, this is probably not worth adding to
the language.

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



More information about the users mailing list