Ignore:
Timestamp:
Apr 24, 2025, 6:35:41 PM (5 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Children:
6b33e89, f85de47
Parents:
f632bd50
Message:

proofreading intro and background chapters, capitalize section titles, update backtick calls to regular calls

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/mike_brooks_MMath/background.tex

    rf632bd50 rb195498  
    44
    55
    6 \section{Ill-typed expressions}
     6\section{Ill-Typed Expressions}
    77
    88C reports many ill-typed expressions as warnings.
     
    2424Clearly, @gcc@ understands these ill-typed case, and yet allows the program to compile, which seems inappropriate.
    2525Compiling with flag @-Werror@, which turns warnings into errors, is often too pervasive, because some warnings are just warnings, \eg an unused variable.
    26 In the following discussion, ``ill-typed'' means giving a nonzero @gcc@ exit condition with a message that discusses typing.
     26In the following discussion, \emph{ill-typed} means giving a nonzero @gcc@ exit condition with a message that discusses typing.
    2727Note, \CFA's type-system rejects all these ill-typed cases as type mismatch errors.
    2828
     
    3737% *1  TAPL-pg1 definition of a type system
    3838
    39 
    40 \section{Reading declarations}
    41 
    42 A significant area of confusion for reading C declarations results from:
    43 \begin{itemize}
     39% reading C declaration: https://c-faq.com/decl/spiral.anderson.html
     40
     41
     42\section{Reading Declarations}
     43
     44A significant area of confusion is reading C declarations, which results from interesting design choices.
     45\begin{itemize}[leftmargin=*]
    4446\item
    45 C is unique in having dimension be higher priority than pointer in declarations.\footnote{
    46 For consistency, subscript has higher priority than dereference, yielding \lstinline{(*arp)[3]} rather than \lstinline{*arp[3]}.}
     47In C, it is possible to have a value and a pointer to it.
     48\begin{cfa}
     49int i = 3, * pi = &i;
     50\end{cfa}
     51Extending this idea, it should be possible to have an array of values and pointer to it.
     52\begin{cfa}
     53int a[5] = { 1, 2, 3, 4, 5 },  * pa[5] = &a;
     54\end{cfa}
     55However, the declaration of @pa@ is incorrect because dimension has higher priority than pointer, so the declaration means an array of 5 pointers to integers.
     56The declarations for the two interpretations of @* [5]@ are:
     57\begin{cquote}
     58\begin{tabular}[t]{@{}ll@{\hspace{15pt}}|@{\hspace{15pt}}ll@{}}
     59\begin{cfa}
     60int (* pa)[5]
     61\end{cfa}
     62&
     63\raisebox{-0.4\totalheight}{\includegraphics{PtrToArray.pdf}}
     64&
     65\begin{cfa}
     66int * ap[5]
     67\end{cfa}
     68&
     69\raisebox{-0.75\totalheight}{\includegraphics{ArrayOfPtr.pdf}}
     70\end{tabular}
     71\end{cquote}
     72If the priorities of dimension and pointer were reversed, the declarations become more intuitive: @int * pa[5]@ and @int * (ap[5])@.
    4773\item
    48 Embedding a declared variable in a declaration, mimics the way the variable is used in executable statements.
     74This priority inversion extends into an expression between dereference and subscript, so usage syntax mimics declaration.
     75\begin{cquote}
     76\setlength{\tabcolsep}{20pt}
     77\begin{tabular}{@{}ll@{}}
     78\begin{cfa}
     79int (* pa)[5]
     80      (*pa)[i] += 1;
     81\end{cfa}
     82&
     83\begin{cfa}
     84int * ap[5]
     85      *ap[i] += 1;
     86\end{cfa}
     87\end{tabular}
     88\end{cquote}
     89(\VRef{s:ArraysDecay} shows pointer decay allows the first form to be written @pa[i] += 1@, which is further syntax confusion.)
     90Again, if the priorities were reversed, the expressions become more intuitive: @*pa[i] += 1@ and @*(ap[i]) += 1@.
     91Note, a similar priority inversion exists between deference @*@ and field selection @.@ (period), so @*ps.f@ means @*(ps.f)@;
     92this anomaly is \emph{fixed} with operator @->@, which performs the two operations in the more intuitive order: @sp->f@ $\Rightarrow$ @(*sp).f@.
    4993\end{itemize}
    50 \begin{cquote}
    51 \begin{tabular}{@{}ll@{}}
    52 \multicolumn{1}{@{}c}{\textbf{Array}} & \multicolumn{1}{c@{}}{\textbf{Function Pointer}} \\
    53 \begin{cfa}
    54 int @(*@ar@)[@5@]@; // definition
    55   ... @(*@ar@)[@3@]@ += 1; // usage
    56 \end{cfa}
    57 &
    58 \begin{cfa}
    59 int @(*@f@())[@5@]@ { ... }; // definition
    60   ... @(*@f@())[@3@]@ += 1; // usage
    61 \end{cfa}
    62 \end{tabular}
    63 \end{cquote}
    64 The parenthesis are necessary to achieve a pointer to a @T@, and the type is wrapped around the name in successive layers (like an \Index{onion}) to match usage in an expression.
    65 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise:
     94While attempting to make the declaration and expression contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise:
    6695\begin{quote}
    6796In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93}
    6897\end{quote}
    6998After all, reading a C array type is easy: just read it from the inside out, and know when to look left and when to look right!
    70 
    71 \CFA provides its own type, variable and routine declarations, using a simpler syntax.
     99Unfortunately, \CFA cannot correct these operator priority inversions without breaking C compatibility.
     100
     101The alternative solution is for \CFA to provide its own type, variable and routine declarations, using a more intuitive syntax.
    72102The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type.
    73 The qualifiers have the same syntax and semantics in \CFA as in C.
    74 Then, a \CFA declaration is read left to right, where a function return type is enclosed in brackets @[@\,@]@.
     103The qualifiers have the same syntax and semantics in \CFA as in C, so there is nothing to learn.
     104Then, a \CFA declaration is read left to right, where a function return-type is enclosed in brackets @[@\,@]@.
    75105\begin{cquote}
    76106\begin{tabular}{@{}l@{\hspace{3em}}ll@{}}
     
    98128\end{tabular}
    99129\end{cquote}
    100 As declaration size increases, it becomes corresponding difficult to read and understand the C declaration form, whereas reading and understanding a \CFA declaration has linear complexity as the declaration size increases.
     130As declaration size increases, it becomes corresponding difficult to read and understand the C form, whereas reading and understanding a \CFA declaration has linear complexity.
    101131Note, writing declarations left to right is common in other programming languages, where the function return-type is often placed after the parameter declarations, \eg \CC \lstinline[language=C++]{auto f( int ) -> int}.
    102 Unfortunately, \CFA cannot interchange the priorities of subscript and dereference in expressions without breaking C compatibility.
     132(Note, putting the return type at the end deviates from where the return value logically appears in an expression, @x = f(...)@ versus @f(...) = x@.)
     133Interestingly, programmers normally speak a declaration from left to right, regardless of how it is written.
     134(It is unclear if Hebrew or Arabic speakers, say declarations right to left.)
    103135
    104136\VRef[Table]{bkgd:ar:usr:avp} introduces the many layers of the C and \CFA array story, where the \CFA story is discussion in \VRef[Chapter]{c:Array}.
     
    168200The conjoining of pointers and arrays could also be applied to structures, where a pointer references a structure field like an array element.
    169201Finally, while subscripting involves pointer arithmetic (as does a field reference @x.y.z@), the computation is complex for multi-dimensional arrays and requires array descriptors to know stride lengths along dimensions.
    170 Many C errors result from manually performing pointer arithmetic instead of using language subscripting, letting the compiler perform any arithmetic.
    171 
    172 Some C textbooks erroneously suggest manual pointer arithmetic is faster than subscripting.
    173 A sound and efficient C program does not require explicit pointer arithmetic.
    174 TODO: provide an example, explain the belief, and give modern refutation
    175 
    176 C semantics wants a programmer to \emph{believe} an array variable is a ``pointer to its first element.''
     202Many C errors result from manually performing pointer arithmetic instead of using language subscripting so the compiler performs the arithmetic.
     203
     204Some modern C textbooks and web sites erroneously suggest manual pointer arithmetic is faster than subscripting.
     205When compiler technology was young, this statement might have been true.
     206However, a sound and efficient C program coupled with a modern C compiler does not require explicit pointer arithmetic.
     207For example, the @gcc@ compiler at @-O3@ generates identical code for the following two summation loops.
     208\begin{cquote}
     209\vspace*{-10pt}
     210\begin{cfa}
     211int a[1000], sum;
     212\end{cfa}
     213\setlength{\tabcolsep}{20pt}
     214\begin{tabular}{@{}ll@{}}
     215\begin{cfa}
     216for ( int i = 0; i < 1000; i += 1 ) {
     217        sum += a[i];
     218}
     219\end{cfa}
     220&
     221\begin{cfa}
     222for ( int * ip = a ; ip < &a[1000]; ip += 1 ) {
     223        sum += *ip;
     224}
     225\end{cfa}
     226\end{tabular}
     227\end{cquote}
     228I believe it is possible to refute any code examples purporting to show pointer arithmetic is faster than subscripting.
     229This believe stems from the performance work I did on \CFA arrays, where it is possible to generate equivalent \CFA subscripting and performance to C subscripting.
     230
     231Unfortunately, C semantics want a programmer to \emph{believe} an array variable is a \emph{pointer to its first element}.
    177232This desire becomes apparent by a detailed inspection of an array declaration.
    178233\lstinput{34-34}{bkgd-carray-arrty.c}
     
    224279
    225280
    226 \subsection{Arrays decay and pointers diffract}
     281\subsection{Arrays Decay and Pointers Diffract}
     282\label{s:ArraysDecay}
    227283
    228284The last section established the difference among these four types:
     
    247303Thus, subscripting happens on pointers not arrays.
    248304
    249 Subscripting proceeds first with pointer decay, if needed.  Next, \cite[\S~6.5.2.1.2]{C11} explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@.
    250 \cite[\S~6.5.6.8]{C11} explains that the addition, of a pointer with an integer type,  is defined only when the pointer refers to an element that is in an array, with a meaning of ``@i@ elements away from,'' which is valid if @ar@ is big enough and @i@ is small enough.
     305Subscripting proceeds first with pointer decay, if needed.
     306Next, \cite[\S~6.5.2.1.2]{C11} explains that @ar[i]@ is treated as if it were @(*((a)+(i)))@.
     307\cite[\S~6.5.6.8]{C11} explains that the addition, of a pointer with an integer type, is defined only when the pointer refers to an element that is in an array, with a meaning of @i@ elements away from, which is valid if @ar@ is big enough and @i@ is small enough.
    251308Finally, \cite[\S~6.5.3.2.4]{C11} explains that the @*@ operator's result is the referenced element.
    252309Taken together, these rules illustrate that @ar[i]@ and @i[a]@ mean the same thing!
     
    285342\end{cfa}
    286343
    287 The shortened parameter syntax @T x[]@ is a further way to spell ``pointer.''
     344The shortened parameter syntax @T x[]@ is a further way to spell \emph{pointer}.
    288345Note the opposite meaning of this spelling now, compared with its use in local variable declarations.
    289346This point of confusion is illustrated in:
     
    321378\begin{table}
    322379\caption{Syntactic Reference for Decay during Parameter-Passing.
    323 Includes interaction with \lstinline{const}ness, where ``immutable'' refers to a restriction on the callee's ability.}
     380Includes interaction with \lstinline{const}ness, where \emph{immutable} refers to a restriction on the callee's ability.}
    324381\label{bkgd:ar:usr:decay-parm}
    325382\centering
     
    357414
    358415
    359 \subsection{Variable Length Arrays}
     416\subsection{Variable-length Arrays}
    360417
    361418As of C99, the C standard supports a \newterm{variable length array} (VLA)~\cite[\S~6.7.5.2.5]{C99}, providing a dynamic-fixed array feature \see{\VRef{s:ArrayIntro}}.
     
    379436% TODO: introduce multidimensional array feature and approaches
    380437
    381 When working with arrays, \eg linear algebra, array dimensions are referred to as ``rows'' and ``columns'' for a matrix, adding ``planes'' for a cube.
     438When working with arrays, \eg linear algebra, array dimensions are referred to as \emph{rows} and \emph{columns} for a matrix, adding \emph{planes} for a cube.
    382439(There is little terminology for higher dimensional arrays.)
    383440For example, an acrostic poem\footnote{A type of poetry where the first, last or other letters in a line spell out a particular word or phrase in a vertical column.}
     
    433490Many languages allow multidimensional arrays-of-arrays, \eg in Pascal or \CC.
    434491\begin{cquote}
     492\setlength{\tabcolsep}{15pt}
    435493\begin{tabular}{@{}ll@{}}
    436494\begin{pascal}
     
    467525
    468526\VRef[Figure]{f:ContiguousNon-contiguous} shows a powerful extension made in C99 for manipulating contiguous \vs non-contiguous arrays.\footnote{C90 also supported non-contiguous arrays.}
    469 For contiguous-array (including VLA) arguments, C99 conjoins one or more of the parameters as a downstream dimension(s), \eg @cols@, implicitly using this parameter to compute the row stride of @m@.
     527For contiguous-array arguments (including VLA), C99 conjoins one or more of the parameters as a downstream dimension(s), \eg @cols@, implicitly using this parameter to compute the row stride of @m@.
    470528There is now sufficient information to support array copying and subscript checking along the columns to prevent changing the argument or buffer-overflow problems, but neither feature is provided.
    471529If the declaration of @fc@ is changed to:
     
    517575
    518576
    519 \subsection{Multi-dimensional arrays decay and pointers diffract}
    520 
    521 As for single-dimension arrays, multi-dimensional arrays have similar issues.
     577\subsection{Multi-Dimensional Arrays Decay and Pointers Diffract}
     578
     579As for single-dimension, multi-dimensional arrays have similar issues \see{\VRef{s:Array}}.
     580Again, the inspection begins by using @sizeof@ to provide program semantics for the intuition of an expression's type.
    522581\lstinput{16-18}{bkgd-carray-mdim.c}
    523 The significant axis of deriving expressions from @ar@ is now ``itself,'' ``first element'' or ``first grand-element (meaning, first element of first element).''
    524 \PAB{Explain, explain, explain.}
     582There are now three axis for deriving expressions from @mx@: \emph{itself}, \emph{first element}, and \emph{first grand-element} (meaning, first element of first element).
    525583\lstinput{20-26}{bkgd-carray-mdim.c}
    526 \PAB{Explain, explain, explain.}
     584Given that arrays are contiguous and the size of @float@ is 4, then the size of @mx@ with 3 $\times$ 10 floats is 120 bytes, the size of its first element (row) is 40 bytes, and the size of the first element of the first row is 4.
     585Again, an array and a point to each of its axes are different.
    527586\lstinput{28-36}{bkgd-carray-mdim.c}
    528 \PAB{Explain, explain, explain.}
     587As well, there is pointer decay from each of the matrix axes to pointers, which all have the same address.
    529588\lstinput{38-44}{bkgd-carray-mdim.c}
     589Finally, subscripting on a @malloc@ result, where the referent may or may not allow subscripting or have the right number of subscripts.
    530590
    531591
     
    533593
    534594Passing an array as an argument to a function is necessary.
    535 Assume a parameter is an array when the function intends to subscript it.
    536 This section asserts that a more satisfactory/formal characterization does not exist in C, surveys the ways that C API authors communicate ``@p@ has zero or more dimensions'' and calls out the minority cases where the C type system is using or verifying such claims.
    537 
    538 A C parameter declarations look different, from the caller's and callee's perspectives.
     595Assume a parameter is an array where the function intends to subscript it.
     596This section asserts that a more satisfactory/formal characterization does not exist in C, then surveys the ways that C API authors communicate @p@ has zero or more dimensions, and finally calls out the minority cases where the C type system is using or verifying such claims.
     597
     598A C parameter declaration looks different from the caller's and callee's perspectives.
    539599Both perspectives consist of the text read by a programmer and the semantics enforced by the type system.
    540 The caller's perspective is available from a function declaration, which allow definition-before-use and separate compilation, but can also be read from (the non-body part of) a function definition.
     600The caller's perspective is available from a function declaration, which allows definition-before-use and separate compilation, but can also be read from (the non-body part of) a function definition.
    541601The callee's perspective is what is available inside the function.
    542602\begin{cfa}
    543 int foo( int, float, char );                            $\C{// declaration, names optional}$
    544 int bar( int i, float f, char c ) {             $\C{// definition, names mandatory}$
    545         // caller's perspective of foo; callee's perspective of bar
     603int foo( int, float, char );                            $\C{// declaration, parameter names optional}$
     604int bar( int i, float f, char c ) {             $\C{// definition, parameter names mandatory}$
     605        // callee's perspective of foo and bar
    546606}
    547 // caller's perspectives of foo's and bar's
    548 \end{cfa}
    549 In caller's perspective, the parameter names (by virtue of being optional) are really comments;
    550 in the callee's perspective, parameter names are semantically significant.
     607// caller's perspectives of foo and bar
     608\end{cfa}
     609From the caller's perspective, the parameter names (by virtue of being optional) are (useful) comments;
     610From the callee's perspective, parameter names are semantically significant.
    551611Array parameters introduce a further, subtle, semantic difference and considerable freedom to comment.
    552612
    553613At the semantic level, there is no such thing as an array parameter, except for one case (@T [static 5]@) discussed shortly.
    554614Rather, there are only pointer parameters.
    555 This fact probably shares considerable responsibility for the common sense of ``an array is just a pointer,'' which has been refuted in non-parameter contexts.
     615This fact probably shares considerable responsibility for the common sense of \emph{an array is just a pointer}, which has been refuted in non-parameter contexts.
    556616This fact holds in both the caller's and callee's perspectives.
    557 However, a parameter's type can include ``array of.'', \eg the type ``pointer to array of 5 ints'' (@T (*)[5]@) is a pointer type.
     617However, a parameter's type can include ``array of'', \eg the type ``pointer to array of 5 ints'' (@T (*)[5]@) is a pointer type.
    558618This type is fully meaningful in the sense that its description does not contain any information that the type system ignores, and the type appears the same in the caller's \vs callee's perspectives.
    559 In fact, the outermost type constructor (syntactically first dimension) is really the one that determines the flavour of parameter.
    560 
    561 Yet, C allows array syntax for the outermost type constructor, from which comes the freedom to comment.
    562 An array parameter declaration can specify the outermost dimension with a dimension value, @[10]@ (which is ignored), an empty dimension list, @[ ]@, or a pointer, @*@, as seen in \VRef[Figure]{f:ArParmEquivDecl}.
    563 The rationale for rejecting the first ``invalid'' row follows shortly, while the second ``invalid'' row is simple nonsense, included to complete the pattern; its syntax hints at what the final row actually achieves.
     619In fact, the outermost type constructor (syntactically first dimension) is really the one that determines the parameter flavour.
    564620
    565621\begin{figure}
    566 \begin{cquote}
    567622\begin{tabular}{@{}llll@{}}
    568623\begin{cfa}
    569624float sum( float a[5] );
    570 float sum( float a[5][4] );
     625float sum( float m[5][4] );
    571626float sum( float a[5][] );
    572627float sum( float a[5]* );
     
    576631\begin{cfa}
    577632float sum( float a[] );
    578 float sum( float a[][4] );
     633float sum( float m[][4] );
    579634float sum( float a[][] );
    580635float sum( float a[]* );
     
    584639\begin{cfa}
    585640float sum( float *a );
    586 float sum( float (*a)[4] );
     641float sum( float (*m)[4] );
    587642float sum( float (*a)[] );
    588643float sum( float (*a)* );
     
    591646&
    592647\begin{cfa}
    593 // ar of float
    594 // mat of float
     648// array of float
     649// matrix of float
    595650// invalid
    596651// invalid
    597 // ar of ptr to float
    598 \end{cfa}
    599 \end{tabular}
    600 \end{cquote}
     652// array of ptr to float
     653\end{cfa}
     654\end{tabular}
    601655\caption{Multiple ways to declare an array parameter.
    602656Across a valid row, every declaration is equivalent.
     
    606660\end{figure}
    607661
    608 In the leftmost style, the typechecker ignores the actual value in most practical cases.
    609 This value is allowed to be a dynamic expression, and then it has practical cases.
    610 \begin{cfa}
    611 void foo( int @n@ ) {
    612         float _42( float @a[n]@ ) {    // nested function
    613                 a[0] = 42;
    614         }
    615         float b[n];
    616         _42( b );
    617 }
     662Yet, C allows array syntax for the outermost type constructor, from which comes the freedom to comment.
     663An array parameter declaration can specify the outermost dimension with a dimension value, @[10]@ (which is ignored), an empty dimension list, @[ ]@, or a pointer, @*@, as seen in \VRef[Figure]{f:ArParmEquivDecl}.
     664The rationale for rejecting the first invalid row follows shortly, while the second invalid row is simple nonsense, included to complete the pattern; its syntax hints at what the final row actually achieves.
     665Note, in the leftmost style, the typechecker ignores the actual value even in a dynamic expression.
     666\begin{cfa}
     667int N;
     668void foo( float @a[N] ) ; // N is ignored
    618669\end{cfa}
    619670
     
    622673% So are @float[5]*@, @float[]*@ and @float (*)*@.  These latter ones are simply nonsense, though they hint at ``1d array of pointers'', whose equivalent syntax options are, @float *[5]@, @float *[]@, and @float **@.
    623674
    624 It is a matter of taste as to whether a programmer should use a form as far left as possible (getting the most out of possible subscripting and dimension sizes), sticking to the right (avoiding false comfort from suggesting the typechecker is checking more than it is), or compromising in the middle (reducing unchecked information, yet clearly stating, ``I will subscript).
     675It is a matter of taste as to whether a programmer should use a form as far left as possible (getting the most out of possible subscripting and dimension sizes), sticking to the right (avoiding false comfort from suggesting the typechecker is checking more than it is), or compromising in the middle (reducing unchecked information, yet clearly stating, ``I will subscript'').
    625676
    626677Note that this equivalence of pointer and array declarations is special to parameters.
     
    635686}
    636687\end{cfa}
    637 This equivalence has the consequence that the type system does not help a caller get it right.
     688Unfortunately, this equivalence has the consequence that the type system does not help a caller get it right.
    638689\begin{cfa}
    639690float sum( float v[] );
     
    656707void foo( int [@const  volatile@ 5] );          $\C{// 5 is ignored}$
    657708\end{cfa}
    658 
    659709To make the first dimension size meaningful, C adds this form.
    660710\begin{cquote}
     
    667717\end{cfa}
    668718Here, the @static@ storage qualifier defines the minimum array size for its argument.
    669 @gcc@ ignores this dimension qualifier, \ie it gives no warning if the argument array size is less than the parameter minimum.  However, @clang@ implements the check, in accordance with the standard.  TODO: be specific about versions
     719Earlier versions of @gcc@ ($<$ 11) and possibly @clang@ ignore this dimension qualifier, while later versions implement the check, in accordance with the standard.
     720
    670721
    671722Note that there are now two different meanings for modifiers in the same position.  In
     
    685736Here, the distance between the first and second elements of each array depends on the inner dimension size.
    686737
    687 This significance of an inner dimension's length is a fact of the callee's perspective.
    688 In the caller's perspective, the type sytem is quite lax.
     738The significance of an inner dimension's length is a fact of the callee's perspective.
     739In the caller's perspective, the type system is quite lax.
    689740Here, there is (some, but) little checking that what is being passed, matches.
    690741% void f( float [][10] );
     
    709760\end{cfa}
    710761The cases without comments are rejections, but simply because the array ranks do not match; in the commented cases, the ranks match and the rules being discussed apply.
    711 The cases @f(b)@ and @f(&a)@ show where some length checking occurs.
    712 But this checking misses the cases @f(d)@ and @f(&c)@, allowing the calls with mismatched lengths, actually 100 for 10.
     762The cases @f( b )@ and @f( &a )@ show where some length checking occurs.
     763But this checking misses the cases @f( d )@ and @f( &c )@, allowing the calls with mismatched lengths, actually 100 for 10.
    713764The C checking rule avoids false alarms, at the expense of safety, by allowing any combinations that involve dynamic values.
    714765Ultimately, an inner dimension's size is a callee's \emph{assumption} because the type system uses declaration details in the callee's perspective that it does not enforce in the caller's perspective.
    715766
    716 Finally, to handle higher-dimensional VLAs, C repurposed the @*@ \emph{within} the dimension in a declaration to mean that the callee has make an assumption about the size, but no (unchecked, possibly wrong) information about this assumption is included for the caller-programmer's benefit/over-confidence.
     767Finally, to handle higher-dimensional VLAs, C repurposed the @*@ \emph{within} the dimension in a declaration to mean that the callee has make an assumption about the size, but no (checked, possibly wrong) information about this assumption is included for the caller-programmer's benefit/\-over-confidence.
    717768\begin{cquote}
    718769@[@ \textit{type-qualifier-list$_{opt}$} @* ]@
     
    731782
    732783
    733 \subsection{Arrays could be values}
     784\subsection{Arrays Could be Values}
    734785
    735786All arrays have a know runtime size at their point of declaration.
     
    751802\begin{cfa}
    752803Jmp_Buf jb1, jb2;
    753 jb1 = jb2;
     804jb1 = jb2;            // copy
    754805void foo( Jmp_Buf );
    755 foo( jb2 );
     806foo( jb2 );           // copy
    756807\end{cfa}
    757808
    758809This same argument applies to returning arrays from functions.
    759 There can be sufficient information to return an array by value but it is not supported.
    760 Again, array wrapping allows an array to be returned from a function and copied into variable.
     810There can be sufficient information to return an array by value but it is unsupported.
     811Again, array wrapping allows an array to be returned from a function and copied into a variable.
    761812
    762813
     
    772823
    773824
    774 \subsection{Design issues}
     825\subsection{Design Issues}
    775826\label{toc:lst:issue}
    776827
    777828This thesis focuses on a reduced design space for linked lists that target \emph{system programmers}.
    778829Within this restricted space, all design-issue discussions assume the following invariants;
    779 alternatives to the assumptions are discussed under Future Work (Section~\ref{toc:lst:futwork}).
     830alternatives to the assumptions are discussed under Future Work (\VRef{toc:lst:futwork}).
    780831\begin{itemize}
    781832        \item A doubly-linked list is being designed.
    782833                Generally, the discussed issues apply similarly for singly-linked lists.
    783                 Circular \vs ordered linking is discussed under List identity (Section~\ref{toc:lst:issue:ident}).
     834                Circular \vs ordered linking is discussed under List identity (\VRef{toc:lst:issue:ident}).
    784835        \item Link fields are system-managed.
    785836                The user works with the system-provided API to query and modify list membership.
     
    790841
    791842
    792 \subsection{Preexisting linked-list libraries}
     843\subsection{Preexisting Linked-List Libraries}
    793844\label{s:PreexistingLinked-ListLibraries}
    794845
     
    799850        \item \CC Standard Template Library's (STL)\footnote{The term STL is contentious as some people prefer the term standard library.} @std::list@\cite{lst:stl}
    800851\end{enumerate}
    801 %A general comparison of libraries' abilities is given under Related Work (Section~\ref{toc:lst:relwork}).
     852%A general comparison of libraries' abilities is given under Related Work (\VRef{toc:lst:relwork}).
    802853For the discussion, assume the fictional type @req@ (request) is the user's payload in examples.
    803854As well, the list library is helping the user manage (organize) requests, \eg a request can be work on the level of handling a network arrival-event or scheduling a thread.
    804855
    805856
    806 \subsection{Link attachment: intrusive vs.\ wrapped}
     857\subsection{Link Attachment: Intrusive \vs Wrapped}
    807858\label{toc:lst:issue:attach}
    808859
     
    837888                Three styles of link attachment: (a)~intrusive, (b)~wrapped reference, and (c)~wrapped value.
    838889                The diagrams show the memory layouts that result after the code runs, eliding the head object \lstinline{reqs};
    839                 head objects are discussed in Section~\ref{toc:lst:issue:ident}.
     890                head objects are discussed in \VRef{toc:lst:issue:ident}.
    840891                In (a), the field \lstinline{req.x} names a list direction;
    841                 these are discussed in Section~\ref{toc:lst:issue:simultaneity}.
     892                these are discussed in \VRef{toc:lst:issue:simultaneity}.
    842893                In (b) and (c), the type \lstinline{node} represents a system-internal type,
    843894                which is \lstinline{std::_List_node} in the GNU implementation.
     
    889940                % \protect\subref*{f:Intrusive}~intrusive, \protect\subref*{f:WrappedRef}~wrapped reference, and \protect\subref*{f:WrappedValue}~wrapped value.
    890941                The diagrams show the memory layouts that result after the code runs, eliding the head object \lstinline{reqs};
    891                 head objects are discussed in Section~\ref{toc:lst:issue:ident}.
     942                head objects are discussed in \VRef{toc:lst:issue:ident}.
    892943                In \protect\subref*{f:Intrusive}, the field \lstinline{req.d} names a list direction;
    893                 these are discussed in Section~\ref{toc:lst:issue:simultaneity}.
     944                these are discussed in \VRef{toc:lst:issue:simultaneity}.
    894945                In \protect\subref*{f:WrappedRef} and \protect\subref*{f:WrappedValue}, the type \lstinline{node} represents a
    895946                library-internal type, which is \lstinline{std::_List_node} in the GNU implementation
     
    905956In all three cases, a @req@ object can enter and leave a list many times.
    906957However, in intrusive a @req@ can only be on one list at a time, unless there are separate link-fields for each simultaneous list.
    907 In wrapped reference, a @req@ can appear multiple times on the same or different lists simultaneously, but since @req@ is shared via the pointer, care must be taken if updating data also occurs simultaneously, \eg concurrency.
     958In wrapped reference, a @req@ can appear multiple times on the same or different lists, but since @req@ is shared via the pointer, care must be taken if updating data also occurs simultaneously, \eg concurrency.
    908959In wrapped value, the @req@ is copied, which increases storage usage, but allows independent simultaneous changes;
    909 however, knowing which of the @req@ object is the ``true'' object becomes complex.
     960however, knowing which of the @req@ object is the \emph{true} object becomes complex.
    910961\see*{\VRef{toc:lst:issue:simultaneity} for further discussion.}
    911962
    912963The implementation of @LIST_ENTRY@ uses a trick to find the links and the node containing the links.
    913 The macro @LIST_INSERT_HEAD(&reqs, &r2, d);@ takes the list header, a pointer to the node, and the offset of the link fields in the node.
     964The macro @LIST_INSERT_HEAD( &reqs, &r2, d )@ takes the list header, a pointer to the node, and the offset of the link fields in the node.
    914965One of the fields generated by @LIST_ENTRY@ is a pointer to the node, which is set to the node address, \eg @r2@.
    915966Hence, the offset to the link fields provides an access to the entire node, \ie the node points at itself.
    916 For list traversal, @LIST_FOREACH(cur, &reqs_pri, by_pri)@, there is the node cursor, the list, and the offset of the link fields within the node.
     967For list traversal, @LIST_FOREACH( cur, &reqs_pri, by_pri )@, there is the node cursor, the list, and the offset of the link fields within the node.
    917968The traversal actually moves from link fields to link fields within a node and sets the node cursor from the pointer within the link fields back to the node.
    918969
     
    926977Another subtle advantage of intrusive arrangement is that a reference to a user-level item (@req@) is sufficient to navigate or manage the item's membership.
    927978In LQ, the intrusive @req@ pointer is the right argument type for operations @LIST_NEXT@ or @LIST_REMOVE@;
    928 there is no distinguishing a @req@ from ``a @req@ in a list.''
     979there is no distinguishing a @req@ from a @req@ in a list.
    929980The same is not true of STL, wrapped reference or value.
    930981There, the analogous operations, @iterator::operator++()@, @iterator::operator*()@, and @list::erase(iterator)@, work on a parameter of type @list<T>::iterator@;
     
    946997                the LQ C macros do not expand to valid C++ when instantiated with template parameters---there is no \lstinline{struct El}.
    947998                When using a custom-patched version of LQ to work around this issue,
    948                 the programs of Figure~\ref{f:WrappedRef} and wrapped value work with this shim in place of real STL.
     999                the programs of \VRef[Figure]{f:WrappedRef} and wrapped value work with this shim in place of real STL.
    9491000                Their executions lead to the same memory layouts.
    9501001        }
     
    9521003\end{figure}
    9531004
    954 It is possible to simulate wrapped using intrusive, illustrated in Figure~\ref{fig:lst-issues-attach-reduction}.
     1005It is possible to simulate wrapped using intrusive, illustrated in \VRef[Figure]{fig:lst-issues-attach-reduction}.
    9551006This shim layer performs the implicit dynamic allocations that pure intrusion avoids.
    9561007But there is no reduction going the other way.
     
    9611012An intrusive-primitive library like LQ lets users choose when to make this tradeoff.
    9621013A wrapped-primitive library like STL forces users to incur the costs of wrapping, whether or not they access its benefits.
    963 
    964 
    965 \subsection{Simultaneity: single vs.\ multi-static vs.\ dynamic}
     1014\CFA is capable of supporting a wrapped library, if need arose.
     1015
     1016
     1017\subsection{Simultaneity: Single \vs Multi-Static \vs Dynamic}
    9661018\label{toc:lst:issue:simultaneity}
    9671019
     
    9861038\newterm{Simultaneity} deals with the question:
    9871039In how many different lists can a node be stored, at the same time?
    988 Figure~\ref{fig:lst-issues-multi-static} shows an example that can traverse all requests in priority order (field @pri@) or navigate among requests with the same request value (field @rqr@).
     1040\VRef[Figure]{fig:lst-issues-multi-static} shows an example that can traverse all requests in priority order (field @pri@) or navigate among requests with the same request value (field @rqr@).
    9891041Each of ``by priority'' and ``by common request value'' is a separate list.
    9901042For example, there is a single priority-list linked in order [1, 2, 2, 3, 3, 4], where nodes may have the same priority, and there are three common request-value lists combining requests with the same values: [42, 42], [17, 17, 17], and [99], giving four head nodes one for each list.
     
    9961048This feature is used in the \CFA runtime, where a thread node may be on a blocked or running list, but never on both simultaneously.
    9971049
    998 Now consider the STL in the wrapped-reference arrangement of Figure~\ref{f:WrappedRef}.
     1050Now consider the STL in the wrapped-reference arrangement of \VRef[Figure]{f:WrappedRef}.
    9991051Here it is possible to construct the same simultaneity by creating multiple STL lists, each pointing at the appropriate nodes.
    10001052Each group of intrusive links become the links for each separate STL list.
     
    10031055Note, it might be possible to wrap the multiple lists in another type to hide this implementation issue.
    10041056
    1005 Now consider the STL in the wrapped-value arrangement of Figure~\ref{f:WrappedValue}.
     1057Now consider the STL in the wrapped-value arrangement of \VRef[Figure]{f:WrappedValue}.
    10061058Again, it is possible to construct the same simultaneity by creating multiple STL lists, each copying the appropriate nodes, where the intrusive links become the links for each separate STL list.
    10071059The upside is the same as for wrapped-reference arrangement with an unlimited number of list bindings.
     
    10151067% LQ's ergonomics are well-suited to the uncommon case of multiple list directions.
    10161068% Its intrusion declaration and insertion operation both use a mandatory explicit parameter naming the direction.
    1017 % This decision works well in Figure~\ref{fig:lst-issues-multi-static}, where the names @by_pri@ and @by_rqr@ work well,
    1018 % but it clutters Figure~\ref{f:Intrusive}, where a contrived name must be invented and used.
     1069% This decision works well in \VRef[Figure]{fig:lst-issues-multi-static}, where the names @by_pri@ and @by_rqr@ work well,
     1070% but it clutters \VRef[Figure]{f:Intrusive}, where a contrived name must be invented and used.
    10191071% The example uses @x@; @reqs@ would be a more readily ignored choice. \PAB{wording?}
    10201072
     
    10891141
    10901142
    1091 \subsection{User integration: preprocessed vs.\ type-system mediated}
    1092 
    1093 \PAB{What do you want to say here?}
     1143\subsection{User Integration: Preprocessed \vs Type-System Mediated}
     1144
     1145While the syntax for LQ is reasonably succinct, it comes at the cost of using C preprocessor macros for generics, which are not part of the language type-system, like \CC templates.
     1146Hence, small errors in macro arguments can lead to large substitution mistakes, as the arguments maybe textually written in many places and/or concatenated with other arguments/text to create new names and expressions.
     1147This can lead to a cascade of error messages that are confusing and difficult to debug.
     1148For example, argument errors like @a.b,c@, comma instead of period, or @by-pri@, minus instead of underscore, can produce many error messages.
     1149
     1150Instead, language function calls (even with inlining) handled argument mistakes locally at the call, giving very specific error message.
     1151\CC @concepts@ were introduced in @templates@ to deal with just this problem.
    10941152
    10951153% example of poor error message due to LQ's preprocessed integration
     
    11011159
    11021160
    1103 \subsection{List identity: headed vs.\ ad-hoc}
     1161\subsection{List Identity: Headed \vs Ad-Hoc}
    11041162\label{toc:lst:issue:ident}
    11051163
    1106 All examples so far use distinct user-facing types:
    1107 an item found in a list (type @req@ of variable @r1@, see \VRef[Figure]{fig:lst-issues-attach}), and a list (type @reql@ of variable @reqs_pri@, see \VRef[Figure]{fig:lst-issues-ident}).
    1108 The latter type is a head.
    1109 The resulting identity model (empty list) is just the head.
    1110 A bespoke ``pointer to next @req@'' implementation often omits the header;
    1111 hence, a pointer to any node can traverse its link fields: right or left and around, depending on the data structure.
    1112 The resulting identity model is ad-hoc.
    1113 
    1114 Figure~\ref{fig:lst-issues-ident} shows the identity model's impact on
    1115 the existence of certain conceptual constructs, like zero-lengths lists and unlisted elements.
    1116 In headed thinking, there are length-zero lists (heads with no elements), and an element can be listed or not listed.
    1117 In ad-hoc thinking, there are no length-zero lists and every element belongs to a list of length at least one.
    1118 By omitting the head, elements can enter into an adjacency relationship, without requiring allocation for a head for the list, or finding a correct existing head.
     1164All examples so far use two distinct types for:
     1165an item found in a list (type @req@ of variable @r1@, see \VRef[Figure]{fig:lst-issues-attach}), and the list (type @reql@ of variable @reqs_pri@, see \VRef[Figure]{fig:lst-issues-ident}).
     1166This kind of list is ``headed'', where the empty list is just a head.
     1167An alternate ``ad-hoc'' approach omits the header, where the empty list is no nodes.
     1168Here, a pointer to any node can traverse its link fields: right or left and around, depending on the data structure.
     1169Note, a headed list is superset of an ad-hoc list, and can normally perform all of the ad-hoc operations.
     1170\VRef[Figure]{fig:lst-issues-ident} shows both approaches for different list lengths and unlisted elements.
     1171For headed, there are length-zero lists (heads with no elements), and an element can be listed or not listed.
     1172For ad-hoc, there are no length-zero lists and every element belongs to a list of length at least one.
    11191173
    11201174\begin{figure}
     
    11281182\end{figure}
    11291183
    1130 A head defines one or more element roles, among elements that share a transitive adjacency.
    1131 ``First'' and ``last'' are element roles.
    1132 One moment's ``first'' need not be the next moment's.
    1133 
    1134 There is a cost to maintaining these roles.
     1184The purpose of a header is to provide specialized but implicit node access, such as the first/last nodes in the list, where accessing these nodes is deemed a commonly occurring operation and should be $O(1)$ for performance of certain operations.
     1185For example, without a last pointer in a singly-linked list, adding to the end of the list is an $O(N)$ operation to traverse the list to find the last node.
     1186Without the header, this specialized information must be managed explicitly, where the programmer builds their own external, equivalent header information.
     1187However, external management of particular nodes might not be beneficial because the list does not provide operations that can take advantage of them, such as using an external pointer to update an internal link.
     1188Clearly, there is a cost maintaining this specialized information, which needs to be amortized across the list operations that use it, \eg rarely adding to the end of a list.
    11351189A runtime component of this cost is evident in LQ's offering the choice of type generators @LIST@ \vs @TAILQ@.
    1136 Its @LIST@ maintains a ``first,'' but not a ``last;'' its @TAILQ@ maintains both roles.
     1190Its @LIST@ maintains a \emph{first}, but not a \emph{last};
     1191its @TAILQ@ maintains both roles.
    11371192(Both types are doubly linked and an analogous choice is available for singly linked.)
    11381193
    1139 TODO: finish making this point
    1140 
    1141 See WIP in lst-issues-adhoc-*.ignore.*.
    1142 
    1143 The code-complexity component of the cost ...
    1144 
    1145 Ability to offer heads is good.  Point: Does maintaining a head mean that the user has to provide more state when manipulating the list?  Requiring the user to do so is bad, because the user may have lots of "list" typed variables in scope, and detecting that the user passed the wrong one requires testing all the listing edge cases.
    1146 
    1147 
    1148 \subsection{End treatment: cased vs.\ uniform }
    1149 
    1150 A linear (non-circular), nonempty linked-list has a first element and a last element, whether or not the list is headed.
    1151 A first element has no predecessor and a last element has no successor.
     1194
     1195\subsection{End Treatment: Cased \vs Uniform }
     1196
     1197All lists must have a logical \emph{beginning/ending}, otherwise list traversal is infinite.
     1198\emph{End treatment} refers to how the list represents the lack of a predecessor/successor to demarcate end point(s).
     1199For example, in a doubly-linked list containing a single node, the next/prev links have no successor/predecessor nodes.
     1200Note, a list does not need to use links to denote its size;
     1201it can use a node counter in the header, where $N$ node traversals indicates complete navigation of the list.
     1202However, managing the number of nodes is an additional cost, as the links must always be managed.
     1203
     1204The following discussion refers to the LQ representations, detailed in \VRef[Figure]{fig:lst-issues-end}, using a null pointer to mark end points.
     1205LQ uses this representation for its successor/last.
     1206For example, consider the operation of inserting after a given element.
     1207A doubly-linked list must update the given node's successor, to make its predecessor-pointer refer to the new node.
     1208This step must happen when the given node has a successor (when its successor pointer is non-null),
     1209and must be skipped when it does not (when its successor pointer cannot be navigated).
     1210So this operation contains a branch, to decide which case is happening.
     1211All branches have pathological cases where branch prediction's success rate is low and the execution pipeline stalls often.
     1212Hence, this issue is relevant to achieving high performance.
    11521213
    11531214\begin{figure}
     
    11641225\end{figure}
    11651226
    1166 End treatment refers to how the list represents the lack of a predecessor/successor.
    1167 The following elaboration refers to the LQ representations, detailed in Figure~\ref{fig:lst-issues-end}.
    1168 The most obvious representation, a null pointer, mandates a cased end treatment.
    1169 LQ uses this representation for its successor/last.
    1170 Consider the operation of inserting after a given element.
    1171 A doubly-linked list must update the given node's successor, to make its predecessor-pointer refer to the new node.
    1172 This step must happen when the given node has a successor (when its successor pointer is non-null),
    1173 and must be skipped when it does not (when its successor pointer cannot be navigated).
    1174 So this operation contains a branch, to decide which case is happening.
    1175 All branches have pathological cases where branch prediction's success rate is low and the execution pipeline is stalling often.
    1176 Hence, this issue is implementation-level, relevant to achieving high performance.
    1177 
    1178 This branch is sometimes avoidable; the result is a uniform end treatment.
    1179 Here is one example of such an implementation that works for a headed list.
    1180 LQ uses this representation for its predecessor/first.  (All LQ offerings are headed at the front.)
     1227Interestingly, this branch is sometimes avoidable, giving a uniform end-treatment in the code.
     1228For example, LQ is headed at the front.
    11811229For predecessor/first navigation, the relevant operation is inserting before a given element.
    11821230LQ's predecessor representation is not a pointer to a node, but a pointer to a pseudo-successor pointer.
    11831231When there is a predecessor node, that node contains a real-successor pointer; it is the target of the reference node's predecessor pointer.
    11841232When there is no predecessor node, the reference node (now known to be first node) acts as the pseudo-successor of the list head.
    1185 The list head contains a pointer to the first node.
     1233Now, the list head contains a pointer to the first node.
    11861234When inserting before the first node, the list head's first-pointer is the one that must change.
    1187 So, the first node's ``predecessor'' pointer (to a pseudo-successor pointer) is set as the list head's first-pointer.
     1235So, the first node's \emph{predecessor} pointer (to a pseudo-successor pointer) is set as the list head's first-pointer.
    11881236Now, inserting before a given element does the same logic in both cases:
    1189 follow the guaranteed-non-null predecessor pointer, and update what you find there to refer to the new node.
     1237follow the guaranteed-non-null predecessor pointer, and update that location to refer to the new node.
    11901238Applying this trick makes it possible to have list management routines that are completely free of conditional control-flow.
    11911239Considering a path length of only a few instructions (less than the processor's pipeline length),
Note: See TracChangeset for help on using the changeset viewer.