[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