Fields

A field is a named mutable data item of a record, union or class whose attributes determine its type, modes of use (readable, writable) and visibility (private or not).

There is no support for accessing an arbitrary field of a union because it would not be type-safe to do so. Instead, a union is classified according to its discriminator to get the field in use. For example, see the special structure ClassifyEvent which provides the function classify.

There is no support for accessing a field of a class. Although technically possible, there is currently no requirement to do so.

Referring to fields

A field name is an identifier in the local scope of a record. For a field some_field_name of a record Record in a namespace Namespace, the hierarchical SML name is Namespace.Record.someFieldName.

For example, the field left_margin of the record TextAttributes in the namespace Gtk is Gtk.TextAttributes.leftMargin.

In order to provide a type-safe and mode-safe interface for using fields, each field has an SML specification that constrains the record, the type of the field data and access to the field.

The specification of Namespace.Record.someFieldName in the signature NAMESPACE_RECORD has the form:

  • val someFieldName :
      {
        get : t -> readType,
        set : writeType -> t -> unit
      }

    if the field is readable and writable;

  • val someFieldName : {get : t -> readType}

    if the field is readable and not writable;

  • val someFieldName : {set : writeType -> t -> unit}

    if the field is writable and not readable;

where

readType

is the type of the value read from the field

writeType

is the type of the value written to the field

For example, the specification of the readable and writable field Gtk.TextAttributes.leftMargin in the signature GTK_TEXT_ATTRIBUTES is

val leftMargin :
  {
    get : t -> LargeInt.int,
    set : LargeInt.int -> t -> unit
  }

readType and writeType are not necessarily the same. They differ when the field data has an object type because writeType allows an object of any subclass of the object type but readType does not.

For example, the specification of Gdk.WindowAttr.cursor in the signature GDK_WINDOW is

val cursor :
  {
    get : t -> base cursor_class option,
    set : 'a cursor_class option -> t -> unit
  }

Accessing fields

The value of a field Namespace.Record.field in a struct s is given by

#get Namespace.Record.field s

The above expression does not type check if any of the following are satisfied:

  • s is not an instance of the record Namespace.Record;

  • the field is not readable (so the get accessor is not present).

The value of a field Namespace.Record.field in a struct s is set to x by

#set Namespace.Record.field x s

The above expression does not type check if any of the following are satisfied:

  • s is not an instance of the record Namespace.Record

  • the field is not writable (so the set accessor is not present);

  • the type of x is not an instance of the type of the field data.