Types
Basic types
For each basic type gbasictype, 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.
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.
Array types
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:
C array |
size |
||
zero terminated |
separate parameter |
||
elements |
packed inline |
ElemCArray |
ElemCArrayN |
referenced by a pointer |
ElemCPtrArray |
ElemCPtrArrayN |
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.
Enumeration types
For each enumeration type 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 (bitfield) type 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 BIT_FLAGS 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
Class types
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
'a Namespace.Class.class
where 'a is a type variable. The SML type for Class but not a subclass of Class is
base Namespace.Class.class
which is abbreviated to
Namespace.Class.t
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 object types.
Class encoding
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 mGTK: An SML binding of Gtk+, Section 4.
The object type for a class C or any subclass of C is
'a C.class
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
'b D.class
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
base C.class
This type is abbreviated to
C.t
Given the class hierarchy
C
D
E
F
the following types are equivalent, and may be used interchangeably in type error messages:
'a F.class
'a f E.class
'a f e D.class
'a f e d C.class
Similarly, the following types are equivalent:
F.t
base F.class
base f E.class
base f e D.class
base f e d C.class
Interface types
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.
Implemented interfaces
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.)
Record types
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
Union types
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
'a Namespace.Union.union
where 'a is a type variable. The SML type for an unknown field of Union is
base Namespace.Union.union
which is abbreviated to
Namespace.Union.t
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 ClassifyEvent.classify.