[MLton] A Question on Property-List

Matthew Fluet fluet at tti-c.org
Sat Mar 17 11:51:48 PST 2007


BaoJian Hua wrote:
>     Now I've finished reading some parts of the MLton source code. For the
> property list, we also want to use it in our own compiler project,
> substituting our previous table-based approach. 

You might be interested in this thread, which discusses some of the 
tradeoffs between properties and hash-tables in the context of a compiler:
   http://mlton.org/pipermail/mlton/2004-December/026371.html

 > But as for the documentation
> is rare on it, so I found some code are hard to understand.
>     I've read the related code in the "mlton-20051202/lib/mlton/basic"
> directory:
>          1. het-container.sig{fun}
>          2. property-list.sig{fun}
>          3. property.sig{fun}
> 
>     I'm comfortable with the former two, but I am not able to understand the
> third very well. Would you be so kind as to explain the functionality of the
> third a little detailed?

Essentially, Property provides a mean of manipulating individual 
properties that are stored in an object's property list.  The large 
number of functions in the Property structure corresponds to choices in 
the ways of handling the initialization of properties, whether 
properties are mutable, and ways of removing properties.

Ultimately, one is usually interested in having functions of the form
   X -> Y
and
   X * Y -> unit
where X is the type of some IL object (say, Var.t) and Y is the type of 
some information we want to associate with the object (say, bool).

The simplest Property function is:
   val get : ('sym -> Plist.t) * ('sym, 'val) init
             -> {get: 'sym -> 'val,
                 rem: 'sym -> unit}
The type 'sym is the type of the IL object (X and Var.t above) and 'val 
is the type of information we want to associated with the object (Y and 
bool above).  This function creates a new property that can be stored on 
property lists.

Note that although information will ultimately be stored in a property 
list, it is much more convenient to apply the result "get" and "rem" 
functions to an IL object directly (i.e., to a value of type Var.t), 
rather than always needing to fetch the object's property-list when 
getting a property.

The first argument to "get", of type 'sym -> Plist.t, is a function that 
fetches a property-list from the IL object.  This function is used 
internally to fetch property-lists when we want to get and set properties.

The second argument to "get", of type ('sym, 'val) init, is a property 
initializer.  A property initializer is used when we try to get the 
property value for an IL object before we set the property value.  The 
Property structure provides 4 initializers:
   initConst -- initialize to a constant
   initFun -- initialize with a function
   initRec -- initialize with a function (which has access to the
              property's "get" function, so that the initial property
              value of one object may depend upon the property value of
              other objects)
   initRaise -- raise an error

The result of "get" are two functions.  The function "get" is used to 
get the property value associated with an IL object.  The function "rem" 
is used to remove the property value (and property) associated with an 
IL object.

Internally, the function "get" fetches the IL object's property list, 
and looks for the property.  If the property doesn't exist on the IL 
object's property list, it uses the property initializer to compute an 
initial value, which is stored on the property list, and returned.  If 
the property does exist, its value is returned.

Internally, the function "rem" fetches the IL object's property list and 
removes the property.  If the property doesn't exist on the IL object's 
property list, then "rem" does nothing (in particular, it doesn't call 
the property initializer).

The other Property functions are just variations.

A function that returns a "destroy" function rather than a "rem" 
function simply keeps a list of all the property lists to which the 
property was added.  Then one can call destroy to remove every instance 
of the property.

A function that returns a "set" function allows the property value to be 
explicitly set (rather than just implicitly set by the property 
initializer).

Finally, a function that is named "*SetOnce" will raise an error if the 
property is set more than once for the same IL object.

 > And would give some examples how to use the property,
> such as the ones in "mlton/core-ml/dead-code.sig{fun}?

This is one of the simplest uses.

fun deadCode {prog} =
    let
       (* For each variable (Var.t), associate a boolean (bool),
        * which indicates whether or not the variable is used in the
        * program.
        * We want to get and set the boolean;
        * we want to be able to destroy all instances of the property;
        * we want unset variables to be initialized to false
        *)
       val {get = varIsUsed, set = setVarIsUsed, destroy, ...} =
          Property.destGetSet
          (Var.plist (* : Var.t -> Plist.t *)
          ,Property.initConst false
          )
       (* val varIsUsed : Var.t -> bool
        * val setVarIsUsed : Var.t * bool -> unit
        * val destroy : unit -> unit
        *)

       ... setVarIsUsed (x, true) ... (* sets the property to true for 
variable x *)

       ... isVarUsed x ... (* gets the property for variable x; if the 
property wasn't explicitly set, will return 'false' *)


       val () = destroy () (* destroy all instances of the property; 
this recovers the space used by the property *)
     in {prog = Vector.rev prog}
     end




More information about the MLton mailing list