[MLton-devel] Re: SML Basis review

Matthew Fluet fluet@cs.cornell.edu
Tue, 19 Aug 2003 18:40:36 -0400 (EDT)


> I would appreciate a clarification on one of your comments, for
> page 312. You suggest that the implementation of the PrimIO
> functor will necessarily be inefficient unless the vector and
> array types are accompanied by their slice structures. I don't
> see why this is so. The only non-trivial parts to PRIM_IO are the
> augment functions and openVector. and these at worst need copyVec
> and extract. How would slices help? Thanks.

Well, you've mostly hit the nail on the head: while the "old" Basis
specification had:

val Vector.extract : ('a vector * int * int option) -> 'a vector
val Array.extract : ('a array * int * int option) -> 'a vector

the "new" Basis specification has removed these functions (presumably at
the June 1, 2000 revision labeled: "Added slice structures for arrays and
vectors, and modified array and vector signatures to reflect this.").  The
functionality is available through:

val ArraySlice.vector : 'a ArraySlice.slice -> 'a vector
val VectorSlice.vector : 'a VectorSlice.slice -> 'a vector

Now, one can easily accomplish the same effect with a Vector.tabulate and
{Array,Vector}.sub, but this is probably less efficient.  In MLton (and
presumably in other implementations), {Array,Vector}Slice.vector is
implemented with a Vector.tabulate and {Array,Vector}.unsafeSub; the use
of the unsafeSub is justified by the bounds check done when the slice was
created.  (This is the real "fear" behind asking for an opaque signature
match on ARRAY_SLICE structures on page 123.  If a client can "forge" an
'a ArraySlice.slice, then some ArraySlice function that uses unsafeSub and
relies on being passed "good" slices can be fooled into accessing
memory outside the array.)

BTW, I notice that I did not reiterate the comment asking for slice
structures with regards to the StreamIO functor on p. 349.  Again, the
real bother is the lack of Vector.extract.  In fact, for the MLton
implementation, we have an "internal" StreamIOExtra functor that extends
the signature with exactly the necessary extract function.  The "external"
StreamIO functor synthesizes this function from Vector.tabulate and
Vector.sub, but for "internal" uses (i.e., TextIO.StreamIO and
BinIO.StreamIO) we pass in a function synthesized from VectorSlice.vector
and VectorSlice.slice.

The Imperative IO functor (at least a naive version that simply wraps the
StreamIO.{in,out}stream in a ref cell), does not need the slices, but an
imperative buffer as I described previously would benefit from an extract
function.


As a side comment, the PrimIO's reader's readArr and readArrNB functions
and the PrimIO's writer's writeVec, writeVecNB, writeArr, writeArrNB
functions all really operate on slices.  Most everywhere else in the
basis, types of the form {buf: vector, i: int, sz: int option} have been
replaced by vector_slice's.  (The notable exception are the socket I/O
functions, where again, I think slice types would be better.)  Really, the
shame is that all the functionality for dealing with slices in a safe
manner (i.e., without needing to bounds check every operation whose safety
is implied by the validity of the slice) is available in the slice
structures, but one needs to project out of the slice type for I/O, which
will immediately check the validity of the slice before attempting to
perform it's operation.

-Matthew



-------------------------------------------------------
This SF.net email is sponsored by Dice.com.
Did you know that Dice has over 25,000 tech jobs available today? From
careers in IT to Engineering to Tech Sales, Dice has tech jobs from the
best hiring companies. http://www.dice.com/index.epl?rel_code=104
_______________________________________________
MLton-devel mailing list
MLton-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlton-devel