For each basictype, there is an SML structure GBasicType and the corresponding SML type is GBasicType.t. The exception to this is guchar, which is treated as guint8 and does not have its own SML structure. For gint as a file descriptor, the corresponding SML structure is GFileDesc and the corresponding SML type is Posix.ProcEnv.file_desc. These SML types are not abstract but are equivalent to types from the Basis Library.g
structure GChar :> C_SCALAR_EQ_NULL where type t = char structure GBool :> C_SCALAR_EQ where type t = bool structure GShort :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GUShort :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GInt :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GUInt :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GLong :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GULong :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GInt8 :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GUInt8 :> C_SCALAR_EQ_NULL where type t = Word8.word structure GInt16 :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GUInt16 :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GInt32 :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GUInt32 :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GInt64 :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GUInt64 :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GSSize :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GSize :> C_SCALAR_EQ_NULL where type t = LargeInt.int structure GFloat :> C_SCALAR where type t = real structure GDouble :> C_SCALAR where type t = real structure GFileDesc :> C_SCALAR_EQ where type t = Posix.ProcEnv.file_desc
When calling a function with an argument of type LargeInt.int, an exception is raised if the argument is outside the range of the C type of the corresponding parameter.
UTF-8 and file name types
For a C array that represents UTF-8 encoded text or a file name, there is an SML structure Utf8 and the corresponding SML type is Utf8.t. The SML type is not abstract but is equivalent to string from the Basis Library and is, therefore, not mutable.
signature UTF_8 = C_ARRAY where type t = string where type elem = char where type sequence = string structure Utf8 :> UTF_8
Although an SML string can contain UTF-8 encoded text, Basis Library string operations, that assume 8 bit characters, will not generally work. To perform operations on UTF-8 encoded text that is not in the ASCII subset, an alternative library is required.
C array types
For each C array type whose element type has an SML structure Elem, there may be SML structures as follows:
referenced by a pointer
These structures are collectively referred to as ElemC[Ptr]Array[N]. The corresponding SML type is ElemC[Ptr]Array[N].t. The SML type is abstract: internally it is a C array and is, therefore, mutable.
structure ElemCArray :> C_ARRAY where type elem = Elem.t structure ElemCPtrArray :> C_ARRAY where type elem = Elem.t structure ElemCArrayN :> C_ARRAY_N where type elem = Elem.t structure ElemCPtrArrayN :> C_ARRAY_N where type elem = Elem.t
The signature C_ARRAY specifies various array operations. The signature C_ARRAY_N includes C_ARRAY and specifies additional operations that allow the array to be treated as a ‘right hand slice’: the first index is always zero but the last index can be changed to exclude trailing elements in the underlying array.
Each structure ElemC[Ptr]Array[N] exists only if the SML type ElemC[Ptr]Array[N].t is referenced because the family of such structures is infinite, given arrays of arrays.
Note that if Elem is the structure for a named type Namespace.Type:
Elem has the form NamespaceType
The SML type NamespaceTypeC[Ptr]Array[N].t may be referenced from either Namespace or another namespace. In the former case only, the signature NAMESPACE specifies an equivalent local structure TypeC[Ptr]Array[N] so there is an equivalent SML type Namespace.TypeC[Ptr]Array[N].t.
For each Enum in a namespace Namespace, there is an SML structure Namespace.Enum and the SML type for the enumeration is Namespace.Enum.t which is a datatype that has a parameterless constructor for each enumeration literal. The structure Namespace.Enum implements the signature NAMESPACE_ENUM, which has the following form:
signature NAMESPACE_ENUM = sig datatype t = LITERAL_1 | LITERAL_2 | … … end
For example, the structure Gtk.ButtonsType implements the signature GTK_BUTTONS_TYPE, which is defined as follows:
signature GTK_BUTTONS_TYPE = sig datatype t = NONE | OK | CLOSE | CANCEL | YES_NO | OK_CANCEL … end
Flags (bitfield) types
For each Flags in a namespace Namespace, there is an SML structure Namespace.Flags and the SML type for the flags is Namespace.Flags.t. For each predefined flags value VALUE, there is an SML value Namespace.Flags.VALUE. The structure Namespace.Flags implements the signature NAMESPACE_FLAGS, which includes the signature to provide operations on the flags as follows:
signature NAMESPACE_FLAGS = sig eqtype t include BIT_FLAGS where type flags = t val VALUE_1 : t val VALUE_2 : t … end
For example, the structure Gtk.StateFlags implements the signature GTK_STATE_FLAGS, which is defined as follows:
signature GTK_STATE_FLAGS = sig eqtype t include BIT_FLAGS where type flags = t val NORMAL : t val ACTIVE : t val PRELIGHT : t val SELECTED : t val INSENSITIVE : t val INCONSISTENT : t val FOCUSED : t … end
For each class Class in a namespace Namespace, there is an SML structure Namespace.Class.
The SML type for Class or any subclass of Class is
where 'a is a type variable. The SML type for Class but not a subclass of Class is
which is abbreviated to
The structure Namespace.Class implements the signature NAMESPACE_CLASS, which has the following form:
signature NAMESPACE_CLASS = sig type 'a class … type t = base class … end
At run time, an object with type Namespace.Class.t may actually be an instance of a subclass of Class even though the type does not indicate this. The SML types are static and represent what is known at compilation time.
There is also a structure Namespace.ClassClass but applications do not need to use this. Even if Namespace.ClassClass is not referenced in code, it may be referenced in type error messages from a compiler because the type 'a Namespace.ClassClass.class is equivalent to the type 'a Namespace.Class.class.
Unlike an object-oriented language, it is necessary for types to distinguish where an object of any subclass is permitted. Although type safety is guaranteed — a program that incorrectly assumes a subclass is rejected by type checking — it is useful, in practice, to understand the general rule, which is described in the section for.
In order to understand object type errors reported by SML compilers, it is necessary to understand the type encoding for classes because type error messages will be presented in terms of this encoding. The encoding is equivalent to that described in, Section 4.
The object type for a class C or any subclass of C is
The type parameter, indicated by the type variable 'a, may be instantiated to constrain the type to a subclass of C by instantiating it with the witness type of a child class. Each derived class D has its own witness type 'b d that creates a unique type for the class relative to its parent. If D is a child class of C, the object type for D or any subclass of D is
'b d C.class
This type is abbreviated to
In turn, the type parameter, indicated by the type variable 'b, may be instantiated to constrain the type to a subclass of D.
The type for a class is constrained to be none of its subclasses by using the type base for the witness type. Therefore, the type of class C but not a subclass of C is
This type is abbreviated to
Given the class hierarchy
the following types are equivalent, and may be used interchangeably in type error messages:
'a f E.class
'a f e D.class
'a f e d C.class
Similarly, the following types are equivalent:
base f E.class
base f e D.class
base f e d C.class
For each interface Iface in a namespace IfaceNamespace, there is an SML structure IfaceNamespace.Iface and the SML type for the interface is IfaceNamespace.Iface.t. The structure IfaceNamespace.Iface implements the signature IFACE_NAMESPACE_IFACE, which has the following form:
signature IFACE_NAMESPACE_IFACE = sig type t … end
An interface is currently represented as a child class of GObject.Object (the root class). This would be problematic for an interface implemented by a class descended from a different root class. However there are no such interfaces at the moment. Applications should avoid treating an instance of IfaceNamespace.Iface.t as an instance of GObject.Object.t, even though the SML types allow this.
Due to this representation, there is also a structure IfaceNamespace.IfaceClass but applications do not need to use this. Even if IfaceNamespace.IfaceClass is not referenced in code, it may be referenced in type error messages from a compiler because the type 'a IfaceNamespace.IfaceClass.class is equivalent to the type 'a IfaceNamespace.Iface.class.
The type encoding for a class hierarchy captures only the single-inheritance relationship of classes. Therefore, for a class or interface Type in a namespace Namespace that implements an interface Iface in a namespace IfaceNamespace, the SML type Namespace.Type.t is not an instance of IfaceNamespace.Iface.t and explicit conversion is required between these types. Conversion is provided by the function Namespace.Type.asIface which is internally the identity function.
For example, the function Gtk.Button.asActionable converts an instance of 'a Gtk.Button.class to Gtk.Actionable.t.
The specification of Namespace.Type.asIface in the signature NAMESPACE_TYPE has the form
val asIface : 'a class -> IfaceNamespace.Iface.t
if Type is a class;
val asIface : t -> IfaceNamespace.Iface.t
if Type is an interface.
(In the case that IfaceNamespace is the same as Namespace, note that a local name iface_t would be used instead of IfaceNamespace.Iface.t in the above specifications.)
For each record (i.e. struct type) Record in a namespace Namespace, there is an SML structure Namespace.Record and the SML type for the record is Namespace.Record.t. The structure Namespace.Record implements the signature NAMESPACE_RECORD, which has a form equivalent to the following:
signature NAMESPACE_RECORD = sig type t … end
For each union Union in a namespace Namespace, there is an SML structure Namespace.Union.
The SML type for any field of Union or an unknown field of Union is
where 'a is a type variable. The SML type for an unknown field of Union is
which is abbreviated to
The structure Namespace.Union implements the signature NAMESPACE_UNION, which has a form equivalent to the following:
signature NAMESPACE_UNION = sig type 'a union type t = base union val toBase : 'a union -> base union … end
The only union type currently provided by Giraffe Library is Gdk.Event whose classification function is . .classify