I use the name array-with-size to refer to a persistent array with attached size information. Given a viewtype VT, the type for an array-with-size that contains N values of viewtype VT is arrszref(VT, N). Essentially, such a value is a boxed pair of two components of types arrayref(VT, N) and size_t(N). The interfaces for various functions on persistent arrays-with-size can be found in prelude/SATS/arrayref.sats.
For creating an array-with-size, the following functions arrszref_make_arrpsz and arrszref_make_arrayref can be called:
fun{} arrszref_make_arrpsz {a:vt0p}{n:int} (arrpsz(INV(a), n)): arrszref(a) fun{} arrszref_make_arrayref {a:vt0p}{n:int} (arrayref(a, n), size_t(n)): arrszref(a) // end of [arrszref_make_arrayref]
For reading from and writing to an array-with-size, the function templates arrszref_get_at and arrszref_set_at can be used, respectively, which are assigned the following interfaces:
fun{a:t@ype} arrszref_get_at (A: arrszref(a), i: size_t): (a) fun{a:t@ype} arrszref_set_at (A: arrszref(a), i: size_t, x: a): void
As a simple example, the following code implements a function that reverses the content of the array inside a given array-with-size:
fun{a:t@ype} arrszref_reverse ( A: arrszref(a) ) : void = let // val n = A.size() val n2 = half (n) // fun loop (i: size_t): void = let in if i < n2 then let val tmp = A[i] val ni = pred(n)-i in A[i] := A[ni]; A[ni] := tmp; loop (succ(i)) end else () // end of [if] end // end of [loop] // in loop (i2sz(0)) end // end of [arrszref_reverse]
Arrays-with-size can be a good choice over arrays in a prototype implementation as it is often more demanding to program with arrays. Also, for programmers who are yet to become familiar with dependent types, it is definitely easier to work with arrays-with-size than arrays. When programming in ATS, I often start out with arrays-with-size and then replace them with arrays when I can see clear benefits from doing so.
Please find on-line the entirety of the code used in this chapter.