Types defined in a foreign language can be accessed in Mercury using a declaration of the form
:- pragma foreign_type(Lang, MercuryTypeName, ForeignTypeDescriptor).
This defines MercuryTypeName as a synonym for type ForeignTypeDescriptor defined in the foreign language Lang. MercuryTypeName must be the name of an abstract type, or the name of a discriminated union type that is not a subtype. In both cases, MercuryTypeName must be declared with ‘:- type’ as usual. The ‘pragma foreign_type’ must not have wider visibility than the type declaration (if the ‘pragma foreign_type’ declaration is in the interface, the ‘:- type’ declaration must be also).
The type named by MercuryTypeName cannot be the base type of any subtypes (see Subtypes).
ForeignTypeDescriptor defines how the Mercury type is mapped for a particular foreign language. Specific syntax is given in the language specific information below.
MercuryTypeName is treated as an abstract type at all times in Mercury code. However, if MercuryTypeName is one of the parameters of a foreign_proc for Lang, and the ‘pragma foreign_type’ declaration is visible to the foreign_proc, it will be passed to that foreign_proc as specified by ForeignTypeDescriptor.
Multiple foreign language definitions may be given for the same type — the appropriate definition will be used for the appropriate language (see the language specific information below for details). All definitions must have the same visibility. A Mercury definition, which must define a discriminated union type, may also be given. The constructors for the type will only be visible in Mercury clauses for predicates or functions with ‘pragma foreign_proc’ clauses for all of the languages for which there are ‘foreign_type’ declarations for the type.
You can also associate assertions about the properties of the foreign type with the ‘foreign_type’ declaration, using the following syntax:
:- pragma foreign_type(Lang, MercuryTypeName, ForeignTypeDescriptor, [ForeignTypeAssertion, …]).
Currently, three kinds of assertions are supported.
The ‘can_pass_as_mercury_type’ assertion states that on the C backends, values of the given type can be passed to and from Mercury code without boxing, via simple casts, which is faster. This requires the type to be either an integer type or a pointer type, and requires it to be castable to ‘MR_Word’ and back without loss of information (which means that its size may not be greater than the size of ‘MR_Word’).
The ‘word_aligned_pointer’ assertion implies ‘can_pass_as_mercury_type’ and additionally states that values of the given type are pointer values clear in the tag bits. It allows the Mercury implementation to avoid boxing values of the given type when the type appears as the sole argument of a data constructor.
The ‘stable’ assertion is meaningful only in the presence of the ‘can_pass_as_mercury_type’ or ‘word_aligned_pointer’ assertions. It states that either the C type is an integer type, or it is a pointer type pointing to memory that will never change. Together, these assertions are sufficient to allow tabling (see Tabled evaluation) and the ‘compare_representation’ primitive to work on values of such types.
Violations of any of these assertions are very likely to result in the generated executable silently doing the wrong thing, giving no clue to where the problem might be. Since deciding whether a C type satisfies the conditions of these assertions requires knowledge of the internals of the Mercury implementation, we do not recommend the use of any of these assertions unless you are confident of your expertise in those internals.
As with discriminated union types, programmers can specify the unification and/or comparison predicates to use for values of the type using the following syntax (see User-defined equality and comparison):
:- pragma foreign_type(Lang, MercuryTypeName, ForeignTypeDescriptor) where equality is EqualityPred, comparison is ComparePred.
You can use Mercury foreign language interfacing declarations which specify language X to interface to types that are actually written in a different language Y, provided that X and Y have compatible interface conventions. Support for this kind of compatibility is described in the language specific information below.