The fact that reference types are encoded, rather than primitive, brings some
advantages. Among these it is noteworthy that, thanks to the encoding, the default
behavior of the get and set functions can be
modified. So a programmer can define a reference that whenever is read, records
the access in a log file, or it performs some sanity checks before performing a
writing.
For instance the following template program, shows a way to define an integer reference x that whenever it is read executes some extra code, while whenever it is written performs some checks and possibly raises an exception:
let x : ref Int =
let hidden = ref Int 0 in
{ get = (some_extra_code; hidden . get) ;
set = fun (x :Int):[] =
if some_condition
then hidden . set(x)
else raise "Invalid assignment"
}
Another advantage is that it is possible to define the types for read only and write only channels, which can be specialized respectively in a covariant and contravariant way.
For instance if the body of a function performs on some integer reference passed as argument only read operations, then it can specify its input type as fun ( x :{ get = []->T ; ..} ).... In this case the function can accept as argument any reference of type ref S, with S subtype of T.
|