PolyML.SaveState structure

The PolyML.SaveState structure provides a way for a program to save changes without the expense of exporting and building a new executable. Unlike the PolyML.export function which saves the complete state it is possible with the functions in this structure to save just the modifications. In addition it avoids the need for a linker which is needed to turn an exported object file into an executable. Because only the modifications are saved a saved state can only be loaded into the executable that created it.

structure SaveState:
sig
    val saveState : string -> unit
    val loadState : string -> unit
    val saveChild : string * int -> unit
    val renameParent : {child: string, newParent: string} -> unit
    val showHierarchy : unit -> string list
    val showParent : string -> string option
    val loadHierarchy: string list -> unit
    structure Tags:
    sig
        val fixityTag: (string * NameSpace.Infixes.fixity) Universal.tag
        val functorTag: (string * NameSpace.Functors.functorVal) Universal.tag
        val signatureTag: (string * NameSpace.Signatures.signatureVal) Universal.tag
        val structureTag: (string * NameSpace.Structures.structureVal) Universal.tag
        val typeTag: (string * NameSpace.TypeConstrs.typeConstr) Universal.tag
        val valueTag: (string * NameSpace.Values.value) Universal.tag
        val startupTag: (unit -> unit) Universal.tag
    end
    val loadModule: string -> unit
    val loadModuleBasic: string -> Universal.universal list
    val saveModule:
           string *
           {functors: string list,
             onStartup: (unit -> unit) option,
             sigs: string list, structs: string list} -> unit
    val saveModuleBasic: string * Universal.universal list -> unit
end

Simple Saved State

For many purposes the simple saved state is sufficient. This is created with saveState and loaded with loadState.

val saveState : string -> unit
Saves the current state to a file whose name is given as the argument. It saves the current values of all the mutable data (i.e. refs and arrays) that were present in the executable together with any other data that is now reachable from it
val loadState : string -> unit

Loads a saved state file. This overwrites any changes made before the load with the contents of the load file. It does not affect mutables created since the session began nor does it affect function arguments or local variables.

Hierarchical Saved States

The single level saved state created by saveState contains all the data that is accessible by the program apart from immutable data present in the executable. Hierarchical saved states extend this idea by allowing a program to save only the data that is not present in a previously loaded state. Saving a state that contains only the new data creates a "child" of the existing saved state which is the "parent". When the child is loaded in a new session the parent must also be loaded in order to provide the full state. Since the parent may itself be a child of another saved state this forms a chain of related saved states. A particular parent may have several children depending on it. When loadState is called with a file name that refers to a child saved state it automatically loads the parents using information held in each file.

The run-time system retains information about the last file that was loaded or saved and its parents. The information is updated whenever loadState, saveState or saveChild are called.

val showHierarchy : unit -> string list

Returns a list of the file names in the current hierarchy. The first item in the list is the top-most saved state, the next is the immediate child of that state and so on. The last item will be the file name that was actually given as argument to loadState, saveState or saveChild.

val saveChild : string * int -> unit

saveChild (f, n) writes out a saved state to file name f at hierarchy level n. n may be between zero and the current hierarchy level, inclusive. saveState(f) is equivalent to saveChild(f, 0). Typically, saveChild will be called with a new file name and a value for n which is the length of the current hierarchy list. This will make a new child which contains only the information added since the last call to loadState, saveState or saveChild. However, it is possible to use a different value and this will cause the saved state to include data from other saved states of the same or deeper hierarchy.

val renameParent : {child: string, newParent: string} -> unit
val showParent : string -> string option

A child saved state contains the file name of its parent so that when the child is loaded the parent can be loaded automatically. If the parent file is moved for any reason renameParent can be used to modify the parent file name held in a child so that it can be loaded from the new location. showParent returns the current value of the parent file name for a child saved state. If the saved state has no parent showParent returns NONE.

Modules

A module is a collection of bindings, primarily structures, signatures and functors, that can be saved and later reloaded. It is similar to a saved state in that a module can only be loaded into the same executable that saved it. However, it is possible to load multiple modules without them interfering.

The module system is designed with two different levels. The high-level functions, loadModule and saveModule are likely to be useful for most purposes while the lower-level functions, loadModuleBasic and saveModuleBasic will only be required in special circumstances.

val loadModule : string -> unit

loadModule takes the name of a module and loads it into memory. The start-up function, if any is executed and if it returns successfully the structures, signatures and other components are added to the name-space. The module name can either be a file path if it contains a directory separator e.g. ./foo or it is looked up in the path given by POLYMODPATH.

val saveModule : string *
           {sigs: string list, structs: string list, functors: string list,
            onStartup: (unit -> unit) option} -> unit

saveModule takes a file name and names of structures, signature and functors, together with an optional "on-start-up" function and writes them out as a package.

val loadModuleBasic : string -> Universal.universal list

loadModuleBasic is the low-level version of loadModule. The module name is interpreted in the same way and the module is loaded into memory but instead of executing any start-up function or adding components to the name-space the list of the components as a list of Universal.universal values is returned. It is up to the caller how to interpret the result.

val saveModuleBasic: string * Universal.universal list -> unit

saveModuleBasic is the low-level version of saveModule. It takes a file name and a list of Universal.universal values and saves the result as a module. The entries in the list can contain anything. However if the resulting module is loaded with loadModule certain values will be treated specially. Values tagged using the tags listed in the Tags structure will be added to the name space or in the case of the startUpTag, executed as a start-up function. In particular saveModuleBasic must be used if the module should load values or types rather than structures, functors or signatures.