source: doc/theses/mike_brooks_MMath/array.tex @ dab9fb93

Last change on this file since dab9fb93 was dab9fb93, checked in by Michael Brooks <mlbrooks@…>, 7 months ago

Accept Peter's proofreading and adjustment of examples to current syntax

  • Property mode set to 100644
File size: 29.8 KB
Line 
1\chapter{Array}
2
3
4\section{Features Added}
5
6The present work adds a type @array@ to the \CFA standard library~\cite{Cforall}.
7
8This array's length is statically managed and dynamically valued.  This static management achieves argument safety and suggests a path to subscript safety as future work (TODO: cross reference).
9
10This section presents motivating examples of the new array type's usage and follows up with definitions of the notations that appear.
11
12The core of the new array management is tracking all array lengths in the type system.  Dynamically valued lengths are represented using type variables.  The stratification of type variables preceding object declarations makes a length referenceable everywhere that it is needed.  For example, a declaration can share one length, @N@, among a pair of parameters and the return.
13\lstinputlisting[language=CFA, firstline=10, lastline=17]{hello-array.cfa}
14Here, the function @f@ does a pointwise comparison, checking if each pair of numbers is within half a percent of each other, returning the answers in a newly allocated @bool@ array.
15
16The array type uses the parameterized length information in its @sizeof@ determination, illustrated in the example's call to @alloc@.  That call requests an allocation of type @array(bool, N)@, which the type system deduces from the left-hand side of the initialization, into the return type of the @alloc@ call.  Preexisting \CFA behaviour is leveraged here, both in the return-type-only polymorphism, and the @sized(T)@-aware standard-library @alloc@ routine.  The new @array@ type plugs into this behaviour by implementing the @sized@/@sizeof@ assertion to have the intuitive meaning.  As a result, this design avoids an opportunity for programmer error by making the size/length communication to a called routine implicit, compared with C's @calloc@ (or the low-level \CFA analog @aalloc@), which take an explicit length parameter not managed by the type system.
17
18\VRef[Figure]{f:fHarness} shows the harness to use the @f@ function illustrating how dynamic values are fed into the system.
19Here, the @a@ array is loaded with decreasing values, and the @b@ array with amounts off by a constant, giving relative differences within tolerance at first and out of tolerance later.  The program main is run with two different inputs of sequence length.
20
21\begin{figure}
22\lstinputlisting[language=CFA, firstline=30, lastline=49]{hello-array.cfa}
23\caption{\lstinline{f} Harness}
24\label{f:fHarness}
25\end{figure}
26
27The loops in the program main follow the more familiar pattern of using the ordinary variable @n@ to convey the length.  The type system implicitly captures this value at the call site (@main@ calling @f@) and makes it available within the callee (@f@'s loop bound).
28
29The two parts of the example show @n@ adapting a variable into a type-system managed length (at @main@'s declarations of @a@, @b@, and @result@), @N@ adapting in the opposite direction (at @f@'s loop bound), and a pass-thru use of a managed length (at @f@'s declaration of @ret@).
30
31The @forall( ...[N] )@ participates in the user-relevant declaration of the name @N@, which becomes usable in parameter/return declarations and in the function @b@. The present form is chosen to parallel the existing @forall@ forms:
32\begin{cfa}
33forall( @[N]@ ) ... // array kind
34forall( & T  ) ...  // reference kind (dtype)
35forall( T  ) ...    // value kind (otype)
36\end{cfa}
37
38The notation @array(thing, N)@ is a single-dimensional case, giving a generic type instance.
39In summary:
40\begin{itemize}
41\item
42@[N]@ -- within a forall, declares the type variable @N@ to be a managed length
43\item
44$e$ -- a type representing the value of $e$ as a managed length, where $e$ is a @size_t@-typed expression
45\item
46N -- an expression of type @size_t@, whose value is the managed length @N@
47\item
48@array( thing, N0, N1, ... )@ -- a type wrapping $\prod_i N_i$ adjacent occurrences of @thing@ objects
49\end{itemize}
50Unsigned integers have a special status in this type system.  Unlike how C++ allows @template< size_t N, char * msg, typename T >...@ declarations, \CFA does not accommodate values of any user-provided type.  TODO: discuss connection with dependent types.
51
52An example of a type error demonstrates argument safety.  The running example has @f@ expecting two arrays of the same length.  A compile-time error occurs when attempting to call @f@ with arrays whose lengths may differ.
53\lstinputlisting[language=CFA, firstline=60, lastline=65]{hello-array.cfa}
54As is common practice in C, the programmer is free to cast, to assert knowledge not shared with the type system.
55\lstinputlisting[language=CFA, firstline=70, lastline=75]{hello-array.cfa}
56
57Argument safety and the associated implicit communication of array length work with \CFA's generic types too.
58\CFA allows aggregate types to be generalized with multiple type parameters, including parameterized element type, so can it be defined over a parameterized length.
59Doing so gives a refinement of C's ``flexible array member'' pattern, that allows nesting structures with array members anywhere within other structures.
60\lstinputlisting[language=CFA, firstline=10, lastline=16]{hello-accordion.cfa}
61This structure's layout has the starting offset of @cost_contribs@ varying in @Nclients@, and the offset of @total_cost@ varying in both generic parameters.  For a function that operates on a @request@ structure, the type system handles this variation transparently.
62\lstinputlisting[language=CFA, firstline=40, lastline=47]{hello-accordion.cfa}
63In the example, different runs of the program result in different offset values being used.
64\lstinputlisting[language=CFA, firstline=60, lastline=76]{hello-accordion.cfa}
65The output values show that @summarize@ and its caller agree on both the offsets (where the callee starts reading @cost_contribs@ and where the callee writes @total_cost@).  Yet the call site still says just, ``pass the request.''
66
67
68\section{Multidimensional implementation}
69\label{toc:mdimpl}
70
71
72TODO: introduce multidimensional array feature and approaches
73
74The new \CFA standard library @array@ datatype supports multidimensional uses more richly than the C array.  The new array's multidimensional interface and implementation, follows an array-of-arrays setup, meaning, like C's @float[n][m]@ type, one contiguous object, with coarsely-strided dimensions directly wrapping finely-strided dimensions.  This setup is in contrast with the pattern of array of pointers to other allocations representing a sub-array.  Beyond what C's type offers, the new array brings direct support for working with a noncontiguous array slice, allowing a program to work with dimension subscripts given in a non-physical order.  C and C++ require a programmer with such a need to manage pointer/offset arithmetic manually.
75
76Examples are shown using a $5 \times 7$ float array, @a@, loaded with increments of $0.1$ when stepping across the length-7 finely-strided dimension shown on columns, and with increments of $1.0$ when stepping across the length-5 coarsely-strided dimension shown on rows.
77\lstinputlisting[language=CFA, firstline=120, lastline=126]{hello-md.cfa}
78The memory layout of @a@ has strictly increasing numbers along its 35 contiguous positions.
79
80A trivial form of slicing extracts a contiguous inner array, within an array-of-arrays.  Like with the C array, a lesser-dimensional array reference can be bound to the result of subscripting a greater-dimensional array, by a prefix of its dimensions.  This action first subscripts away the most coarsely strided dimensions, leaving a result that expects to be be subscripted by the more finely strided dimensions.
81\lstinputlisting[language=CFA, firstline=60, lastline=66]{hello-md.cfa}
82\lstinputlisting[aboveskip=0pt, language=CFA, firstline=140, lastline=140]{hello-md.cfa}
83
84This function declaration is asserting too much knowledge about its parameter @c@, for it to be usable for printing either a row slice or a column slice.  Specifically, declaring the parameter @c@ with type @array@ means that @c@ is contiguous.  However, the function does not use this fact.  For the function to do its job, @c@ need only be of a container type that offers a subscript operator (of type @ptrdiff_t@ $\rightarrow$ @float@), with managed length @N@.  The new-array library provides the trait @ix@, so-defined.  With it, the original declaration can be generalized, while still implemented with the same body, to the latter declaration:
85\lstinputlisting[language=CFA, firstline=40, lastline=44]{hello-md.cfa}
86\lstinputlisting[aboveskip=0pt, language=CFA, firstline=145, lastline=145]{hello-md.cfa}
87
88Nontrivial slicing, in this example, means passing a noncontiguous slice to @print1d@.  The new-array library provides a ``subscript by all'' operation for this purpose.  In a multi-dimensional subscript operation, any dimension given as @all@ is left ``not yet subscripted by a value,'' implementing the @ix@ trait, waiting for such a value.
89\lstinputlisting[language=CFA, firstline=150, lastline=151]{hello-md.cfa}
90
91The example has shown that @a[2]@ and @a[[2, all]]@ both refer to the same, ``2.*'' slice.  Indeed, the various @print1d@ calls under discussion access the entry with value 2.3 as @a[2][3]@, @a[[2,all]][3]@, and @a[[all,3]][2]@.  This design preserves (and extends) C array semantics by defining @a[[i,j]]@ to be @a[i][j]@ for numeric subscripts, but also for ``subscripting by all''.  That is:
92
93\begin{tabular}{cccccl}
94    @a[[2,all]][3]@  &  $=$  &  @a[2][all][3]@  & $=$  &  @a[2][3]@  & (here, @all@ is redundant)  \\
95    @a[[all,3]][2]@  &  $=$  &  @a[all][3][2]@  & $=$  &  @a[2][3]@  & (here, @all@ is effective)
96\end{tabular}
97
98Narrating progress through each of the @-[-][-][-]@ expressions gives, firstly, a definition of @-[all]@, and secondly, a generalization of C's @-[i]@.
99
100\noindent Where @all@ is redundant:
101
102\begin{tabular}{ll}
103    @a@  & 2-dimensional, want subscripts for coarse then fine \\
104    @a[2]@  & 1-dimensional, want subscript for fine; lock coarse = 2 \\
105    @a[2][all]@  & 1-dimensional, want subscript for fine \\
106    @a[2][all][3]@  & 0-dimensional; lock fine = 3
107\end{tabular}
108
109\noindent Where @all@ is effective:
110
111\begin{tabular}{ll}
112    @a@  & 2-dimensional, want subscripts for coarse then fine \\
113    @a[all]@  & 2-dimensional, want subscripts for fine then coarse \\
114    @a[all][3]@  & 1-dimensional, want subscript for coarse; lock fine = 3 \\
115    @a[all][3][2]@  & 0-dimensional; lock coarse = 2
116\end{tabular}
117
118The semantics of @-[all]@ is to dequeue from the front of the ``want subscripts'' list and re-enqueue at its back.  The semantics of @-[i]@ is to dequeue from the front of the ``want subscripts'' list and lock its value to be @i@.
119
120Contiguous arrays, and slices of them, are all realized by the same underlying parameterized type.  It includes stride information in its metatdata.  The @-[all]@ operation is a conversion from a reference to one instantiation, to a reference to another instantiation.  The running example's @all@-effective step, stated more concretely, is:
121
122\begin{tabular}{ll}
123    @a@       & : 5 of ( 7 of float each spaced 1 float apart ) each spaced 7 floats apart \\
124    @a[all]@  & : 7 of ( 5 of float each spaced 7 floats apart ) each spaced 1 float apart
125\end{tabular}
126
127\begin{figure}
128    \includegraphics{measuring-like-layout}
129    \caption{Visualization of subscripting by value and by \lstinline[language=CFA,basicstyle=\ttfamily]{all}, for \lstinline[language=CFA,basicstyle=\ttfamily]{a} of type \lstinline[language=CFA,basicstyle=\ttfamily]{array( float, 5, 7 )}. The horizontal dimension represents memory addresses while vertical layout is conceptual.}
130    \label{fig:subscr-all}
131\end{figure}
132
133\noindent While the latter description implies overlapping elements, Figure \ref{fig:subscr-all} shows that the overlaps only occur with unused spaces between elements.  Its depictions of @a[all][...]@ show the navigation of a memory layout with nontrivial strides, that is, with ``spaced \_ floats apart'' values that are greater or smaller than the true count of valid indices times the size of a logically indexed element.  Reading from the bottom up, the expression @a[all][3][2]@ shows a float, that is masquerading as a @float[7]@, for the purpose of being arranged among its peers; five such occurrences form @a[all][3]@.  The tail of flatter boxes extending to the right of a proper element represents this stretching.  At the next level of containment, the structure @a[all][3]@ masquerades as a @float[1]@, for the purpose of being arranged among its peers; seven such occurrences form @a[all]@.  The vertical staircase arrangement represents this compression, and resulting overlapping.
134
135The new-array library defines types and operations that ensure proper elements are accessed soundly in spite of the overlapping.  The private @arpk@ structure (array with explicit packing) is generic over these two types (and more): the contained element, what it is masquerading as.  This structure's public interface is the @array(...)@ construction macro and the two subscript operators.  Construction by @array@ initializes the masquerading-as type information to be equal to the contained-element information.  Subscripting by @all@ rearranges the order of masquerading-as types to achieve, in general, nontrivial striding.  Subscripting by a number consumes the masquerading-as size of the contained element type, does normal array stepping according to that size, and returns there element found there, in unmasked form.
136
137The @arpk@ structure and its @-[i]@ operator are thus defined as:
138\begin{lstlisting}
139forall( ztype(N),               // length of current dimension
140        dtype(S) | sized(S),    // masquerading-as
141        dtype E_im,             // immediate element, often another array
142        dtype E_base            // base element, e.g. float, never array
143      ) {
144    struct arpk {
145        S strides[N];           // so that sizeof(this) is N of S
146    };
147
148    // expose E_im, stride by S
149    E_im & ?[?]( arpk(N, S, E_im, E_base) & a, ptrdiff_t i ) {
150        return (E_im &) a.strides[i];
151    }
152}
153\end{lstlisting}
154
155An instantiation of the @arpk@ generic is given by the @array(E_base, N0, N1, ...)@ expansion, which is @arpk( N0, Rec, Rec, E_base )@, where @Rec@ is @array(E_base, N1, ...)@.  In the base case, @array(E_base)@ is just @E_base@.  Because this construction uses the same value for the generic parameters @S@ and @E_im@, the resulting layout has trivial strides.
156
157Subscripting by @all@, to operate on nontrivial strides, is a dequeue-enqueue operation on the @E_im@ chain, which carries @S@ instantiations, intact, to new positions.  Expressed as an operation on types, this rotation is:
158\begin{eqnarray*}
159suball( arpk(N, S, E_i, E_b) ) & = & enq( N, S, E_i, E_b ) \\
160enq( N, S, E_b, E_b ) & = & arpk( N, S, E_b, E_b ) \\
161enq( N, S, arpk(N', S', E_i', E_b), E_b ) & = & arpk( N', S', enq(N, S, E_i', E_b), E_b )
162\end{eqnarray*}
163
164
165\section{Bound checks, added and removed}
166
167\CFA array subscripting is protected with runtime bound checks.  Having dependent typing causes the optimizer to remove more of these bound checks than it would without them.  This section provides a demonstration of the effect.
168
169The experiment compares the \CFA array system with the padded-room system [TODO:xref] most typically exemplified by Java arrays, but also reflected in the C++ pattern where restricted vector usage models a checked array.  The essential feature of this padded-room system is the one-to-one correspondence between array instances and the symbolic bounds on which dynamic checks are based.  The experiment compares with the C++ version to keep access to generated assembly code simple.
170
171As a control case, a simple loop (with no reused dimension sizes) is seen to get the same optimization treatment in both the \CFA and C++ versions.  When the programmer treats the array's bound correctly (making the subscript ``obviously fine''), no dynamic bound check is observed in the program's optimized assembly code.  But when the bounds are adjusted, such that the subscript is possibly invalid, the bound check appears in the optimized assembly, ready to catch an occurrence the mistake.
172
173TODO: paste source and assembly codes
174
175Incorporating reuse among dimension sizes is seen to give \CFA an advantage at being optimized.  The case is naive matrix multiplication over a row-major encoding.
176
177TODO: paste source codes
178
179
180
181
182
183\section{Comparison with other arrays}
184
185\CFA's array is the first lightweight application of dependently-typed bound tracking to an extension of C.  Other extensions of C that apply dependently-typed bound tracking are heavyweight, in that the bound tracking is part of a linearly typed ownership system that further helps guarantee statically the validity of every pointer deference.  These systems, therefore, ask the programmer to convince the type checker that every pointer dereference is valid.  \CFA imposes the lighter-weight obligation, with the more limited guarantee, that initially-declared bounds are respected thereafter.
186
187\CFA's array is also the first extension of C to use its tracked bounds to generate the pointer arithmetic implied by advanced allocation patterns.  Other bound-tracked extensions of C either forbid certain C patterns entirely, or address the problem of \emph{verifying} that the user's provided pointer arithmetic is self-consistent.  The \CFA array, applied to accordion structures [TOD: cross-reference] \emph{implies} the necessary pointer arithmetic, generated automatically, and not appearing at all in a user's program.
188
189\subsection{Safety in a padded room}
190
191Java's array [TODO:cite] is a straightforward example of assuring safety against undefined behaviour, at a cost of expressiveness for more applied properties.  Consider the array parameter declarations in:
192
193\begin{tabular}{rl}
194    C      &  @void f( size_t n, size_t m, float a[n][m] );@ \\
195    Java   &  @void f( float[][] a );@
196\end{tabular}
197
198Java's safety against undefined behaviour assures the callee that, if @a@ is non-null, then @a.length@ is a valid access (say, evaluating to the number $\ell$) and if @i@ is in $[0, \ell)$ then @a[i]@ is a valid access.  If a value of @i@ outside this range is used, a runtime error is guaranteed.  In these respects, C offers no guarantees at all.  Notably, the suggestion that @n@ is the intended size of the first dimension of @a@ is documentation only.  Indeed, many might prefer the technically equivalent declarations @float a[][m]@ or @float (*a)[m]@ as emphasizing the ``no guarantees'' nature of an infrequently used language feature, over using the opportunity to explain a programmer intention.  Moreover, even if @a[0][0]@ is valid for the purpose intended, C's basic infamous feature is the possibility of an @i@, such that @a[i][0]@ is not valid for the same purpose, and yet, its evaluation does not produce an error.
199
200Java's lack of expressiveness for more applied properties means these outcomes are possible:
201\begin{itemize}
202    \item @a[0][17]@ and @a[2][17]@ are valid accesses, yet @a[1][17]@ is a runtime error, because @a[1]@ is a null pointer
203    \item the same observation, now because @a[1]@ refers to an array of length 5
204    \item execution times vary, because the @float@ values within @a@ are sometimes stored nearly contiguously, and other times, not at all
205\end{itemize}
206C's array has none of these limitations, nor do any of the ``array language'' comparators discussed in this section.
207
208This Java level of safety and expressiveness is also exemplified in the C family, with the commonly given advice [TODO:cite example], for C++ programmers to use @std::vector@ in place of the C++ language's array, which is essentially the C array.  The advice is that, while a vector is also more powerful (and quirky) than an array, its capabilities include options to preallocate with an upfront size, to use an available bound-checked accessor (@a.at(i)@ in place of @a[i]@), to avoid using @push_back@, and to use a vector of vectors.  Used with these restrictions, out-of-bound accesses are stopped, and in-bound accesses never exercise the vector's ability to grow, which is to say, they never make the program slow to reallocate and copy, and they never invalidate the program's other references to the contained values.  Allowing this scheme the same referential integrity assumption that \CFA enjoys [TODO:xref], this scheme matches Java's safety and expressiveness exactly.  [TODO: decide about going deeper; some of the Java expressiveness concerns have mitigations, up to even more tradeoffs.]
209
210\subsection{Levels of dependently typed arrays}
211
212The \CFA array and the field of ``array language'' comparators all leverage dependent types to improve on the expressiveness over C and Java, accommodating examples such as:
213\begin{itemize}
214    \item a \emph{zip}-style operation that consumes two arrays of equal length
215    \item a \emph{map}-style operation whose produced length matches the consumed length
216    \item a formulation of matrix multiplication, where the two operands must agree on a middle dimension, and where the result dimensions match the operands' outer dimensions
217\end{itemize}
218Across this field, this expressiveness is not just an available place to document such assumption, but these requirements are strongly guaranteed by default, with varying levels of statically/dynamically checked and ability to opt out.  Along the way, the \CFA array also closes the safety gap (with respect to bounds) that Java has over C.
219
220Dependent type systems, considered for the purpose of bound-tracking, can be full-strength or restricted.  In a full-strength dependent type system, a type can encode an arbitrarily complex predicate, with bound-tracking being an easy example.  The tradeoff of this expressiveness is complexity in the checker, even typically, a potential for its nontermination.  In a restricted dependent type system (purposed for bound tracking), the goal is to check helpful properties, while keeping the checker well-behaved; the other restricted checkers surveyed here, including \CFA's, always terminate.  [TODO: clarify how even Idris type checking terminates]
221
222Idris is a current, general-purpose dependently typed programming language.  Length checking is a common benchmark for full dependent type systems.  Here, the capability being considered is to track lengths that adjust during the execution of a program, such as when an \emph{add} operation produces a collection one element longer than the one on which it started.  [TODO: finish explaining what Data.Vect is and then the essence of the comparison]
223
224POINTS:
225here is how our basic checks look (on a system that does not have to compromise);
226it can also do these other cool checks, but watch how I can mess with its conservativeness and termination
227
228Two current, state-of-the-art array languages, Dex\cite{arr:dex:long} and Futhark\cite{arr:futhark:tytheory}, offer offer novel contributions concerning similar, restricted dependent types for tracking array length.  Unlike \CFA, both are garbage-collected functional languages.  Because they are garbage-collected, referential integrity is built-in, meaning that the heavyweight analysis, that \CFA aims to avoid, is unnecessary.  So, like \CFA, the checking in question is a lightweight bounds-only analysis.  Like \CFA, their checks that are conservatively limited by forbidding arithmetic in the depended-upon expression.
229
230
231
232The Futhark work discusses the working language's connection to a lambda calculus, with typing rules and a safety theorem proven in reference to an operational semantics.  There is a particular emphasis on an existential type, enabling callee-determined return shapes. 
233
234Dex uses a novel conception of size, embedding its quantitative information completely into an ordinary type.
235
236Futhark and full-strength dependently typed languages treat array sizes are ordinary values.  Futhark restricts these expressions syntactically to variables and constants, while a full-strength dependent system does not.
237
238CFA's hybrid presentation, @forall( [N] )@, has @N@ belonging to the type system, yet has no instances.  Belonging to the type system means it is inferred at a call site and communicated implicitly, like in Dex and unlike in Futhark.  Having no instances means there is no type for a variable @i@ that constrains @i@ to be in the range for @N@, unlike Dex, [TODO: verify], but like Futhark.
239
240\subsection{Static safety in C extensions}
241
242
243\section{Future Work}
244
245\subsection{Declaration syntax}
246
247\subsection{Range slicing}
248
249\subsection{With a module system}
250
251\subsection{With described enumerations}
252
253A project in \CFA's current portfolio will improve enumerations.  In the incumbent state, \CFA has C's enumerations, unmodified.  I will not discuss the core of this project, which has a tall mission already, to improve type safety, maintain appropriate C compatibility and offer more flexibility about storage use.  It also has a candidate stretch goal, to adapt \CFA's @forall@ generic system to communicate generalized enumerations:
254\begin{lstlisting}
255    forall( T | is_enum(T) )
256    void show_in_context( T val ) {
257        for( T i ) {
258            string decorator = "";
259            if ( i == val-1 ) decorator = "< ready";
260            if ( i == val   ) decorator = "< go"   ;
261            sout | i | decorator;
262        }
263    }
264    enum weekday { mon, tue, wed = 500, thu, fri };
265    show_in_context( wed );
266\end{lstlisting}
267with output
268\begin{lstlisting}
269    mon
270    tue < ready
271    wed < go
272    thu
273    fri
274\end{lstlisting}
275The details in this presentation aren't meant to be taken too precisely as suggestions for how it should look in \CFA.  But the example shows these abilities:
276\begin{itemize}
277    \item a built-in way (the @is_enum@ trait) for a generic routine to require enumeration-like information about its instantiating type
278    \item an implicit implementation of the trait whenever a user-written enum occurs (@weekday@'s declaration implies @is_enum@)
279    \item a total order over the enumeration constants, with predecessor/successor (@val-1@) available, and valid across gaps in values (@tue == 1 && wed == 500 && tue == wed - 1@)
280    \item a provision for looping (the @for@ form used) over the values of the type.
281\end{itemize}
282
283If \CFA gets such a system for describing the list of values in a type, then \CFA arrays are poised to move from the Futhark level of expressiveness, up to the Dex level.
284
285[TODO: introduce Ada in the comparators]
286
287In Ada and Dex, an array is conceived as a function whose domain must satisfy only certain structural assumptions, while in C, C++, Java, Futhark and \CFA today, the domain is a prefix of the natural numbers.  The generality has obvious aesthetic benefits for programmers working on scheduling resources to weekdays, and for programmers who prefer to count from an initial number of their own choosing.
288
289This change of perspective also lets us remove ubiquitous dynamic bound checks.  [TODO: xref] discusses how automatically inserted bound checks can often be optimized away.  But this approach is unsatisfying to a programmer who believes she has written code in which dynamic checks are unnecessary, but now seeks confirmation.  To remove the ubiquitous dynamic checking is to say that an ordinary subscript operation is only valid when it can be statically verified to be in-bound (and so the ordinary subscript is not dynamically checked), and an explicit dynamic check is available when the static criterion is impractical to meet.
290
291[TODO, fix confusion:  Idris has this arrangement of checks, but still the natural numbers as the domain.]
292
293The structural assumptions required for the domain of an array in Dex are given by the trait (there, ``interface'') @Ix@, which says that the parameter @n@ is a type (which could take an argument like @weekday@) that provides two-way conversion with the integers and a report on the number of values.  Dex's @Ix@ is analogous the @is_enum@ proposed for \CFA above.
294\begin{lstlisting}
295interface Ix n
296  get_size n : Unit -> Int
297  ordinal : n -> Int
298  unsafe_from_ordinal n : Int -> n
299\end{lstlisting}
300
301Dex uses this foundation of a trait (as an array type's domain) to achieve polymorphism over shapes.  This flavour of polymorphism lets a function be generic over how many (and the order of) dimensions a caller uses when interacting with arrays communicated with this function.  Dex's example is a routine that calculates pointwise differences between two samples.  Done with shape polymorphism, one function body is equally applicable to a pair of single-dimensional audio clips (giving a single-dimensional result) and a pair of two-dimensional photographs (giving a two-dimensional result).  In both cases, but with respectively dimensioned interpretations of ``size,'' this function requires the argument sizes to match, and it produces a result of the that size.
302
303The polymorphism plays out with the pointwise-difference routine advertising a single-dimensional interface whose domain type is generic.  In the audio instantiation, the duration-of-clip type argument is used for the domain.  In the photograph instantiation, it's the tuple-type of $ \langle \mathrm{img\_wd}, \mathrm{img\_ht} \rangle $.  This use of a tuple-as-index is made possible by the built-in rule for implementing @Ix@ on a pair, given @Ix@ implementations for its elements
304\begin{lstlisting}
305instance {a b} [Ix a, Ix b] Ix (a & b)
306  get_size = \(). size a * size b
307  ordinal = \(i, j). (ordinal i * size b) + ordinal j
308  unsafe_from_ordinal = \o.
309    bs = size b
310    (unsafe_from_ordinal a (idiv o bs), unsafe_from_ordinal b (rem o bs))
311\end{lstlisting}
312and by a user-provided adapter expression at the call site that shows how to indexing with a tuple is backed by indexing each dimension at a time
313\begin{lstlisting}
314    img_trans :: (img_wd,img_ht)=>Real
315    img_trans.(i,j) = img.i.j
316    result = pairwise img_trans
317\end{lstlisting}
318[TODO: cite as simplification of example from https://openreview.net/pdf?id=rJxd7vsWPS section 4]
319
320In the case of adapting this pattern to \CFA, my current work provides an adapter from ``successively subscripted'' to ``subscripted by tuple,'' so it is likely that generalizing my adapter beyond ``subscripted by @ptrdiff_t@'' is sufficient to make a user-provided adapter unnecessary.
321
322\subsection{Retire pointer arithmetic}
Note: See TracBrowser for help on using the repository browser.