SML# Document Version 4.0.0
14 SML# feature: separate compilation

14.4 Opaque types

The principle underlying interface declaration are the following.

  1. 1.

    Define compile-time resources (static entities) such as datatype and exception themselves just the same way as they will be defined in a source file.

  2. 2.

    Declare only the types of runtime resources such as functions and variables.

They are necessary and sufficient information to compile other source file that uses this interface file. However, this principle alone cannot support ML’s information hiding through opaque signatures. For example, in the previous interface file queue.smi, the ’a queue type is explicitly defined to be Q of ’a list * ’a list and this information is open to the user of this interface file, but we often want to hide this implementation details.

To solve this problem, the interface language introduces the following opaque type declarations.

type tyvars tyid (= typeRep)     (* describe paranthesis as they are *)
eqtype tyvars tyid (= typeRep)    (* describe paranthesis as they are *)

These declaration reveals to the compiler that the internal representation of tyid is typeRep but this information is not available to the code that uses this interface file through _require declaration. As in signature, type declaration defines a type on which equality operation is not defined and eqtype declaration defines a type with on which equality operation is define. typeRep is the type constructor that implements the type tyid. For example, consider the following implementation:

type t1 = int
type t2 = int list
type ’a t3 = (’a * ’a) array

One can write the following in the interface file:

type t1 (= int)
type t2 (= list)
type ’a t3 (= array)

If the implementation type is either a record type, tuple type, or function type, then typeRep must be {}, *, or ->, respectively. If the type is defined by datatype, then typeRep must be one of the following according to the definition of its constructors:

  • unit. The type consists only of a single constructor that has no argument.

  • contag. The type consists only of more than one constructors with no argument.

  • boxed. Otherwise.

For example,to make datatype ’a queue declaration in queue.smi, one can write the following.

type ’a queue (= boxed)

Furthermore, as in signature, interface file need not exhaustively list all the resources the implementation may define. Only those resources defined in the interface file become visible to the code that use it through _require declaration.