Changeset 10a9479d for doc/theses


Ignore:
Timestamp:
Nov 23, 2024, 8:28:37 PM (14 months ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
956b389
Parents:
b006c51e (diff), de7b7a5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
doc/theses
Files:
2 added
10 edited
1 moved

Legend:

Unmodified
Added
Removed
  • doc/theses/fangren_yu_MMath/content1.tex

    rb006c51e r10a9479d  
    1 \chapter{Recent Features Introduced to \CFA}
     1\chapter{\CFA Features and Type System Interactions}
    22\label{c:content1}
    33
    4 This chapter discusses some recent additions to the \CFA language and their interactions with the type system.
     4This chapter discusses \CFA feature introduced over time by multiple people and their interactions with the type system.
    55
    66
     
    1717Succinctly, if the address changes often, use a pointer;
    1818if the value changes often, use a reference.
    19 Note, \CC made its reference address immutable starting a \emph{belief} that immutability is a fundamental aspect of a reference's pointer.
    20 The results is asymmetry semantics between the pointer and reference.
     19Java has mutable references but no pointers.
     20\CC has mutable pointers but immutable references;
     21hence, references match with functional programming.
     22However, the consequence is asymmetry semantics between the pointer and reference.
    2123\CFA adopts a uniform policy between pointers and references where mutability is a separate property made at the declaration.
    2224
     
    3638Like pointers, reference can be cascaded, \ie a reference to a reference, \eg @&& r2@.\footnote{
    3739\CC uses \lstinline{&&} for rvalue reference, a feature for move semantics and handling the \lstinline{const} Hell problem.}
    38 Usage of a reference variable automatically performs the same number of dereferences as the number of references in its declaration, \eg @r3@ becomes @***r3@.
     40Usage of a reference variable automatically performs the same number of dereferences as the number of references in its declaration, \eg @r2@ becomes @**r2@.
    3941Finally, to reassign a reference's address needs a mechanism to stop the auto-referencing, which is accomplished by using a single reference to cancel all the auto-dereferencing, \eg @&r3 = &y@ resets @r3@'s address to point to @y@.
    4042\CFA's reference type (including multi-de/references) is powerful enough to describe the lvalue rules in C by types only.
     
    6668int x = 3; $\C{// mutable}$
    6769const int cx = 5; $\C{// immutable}$
    68 int * const cp = &x, $\C{// immutable pointer}$
     70int * const cp = &x, $\C{// immutable pointer pointer/reference}$
    6971        & const cr = cx;
    70 const int * const ccp = &cx, $\C{// immutable value and pointer}$
     72const int * const ccp = &cx, $\C{// immutable value and pointer/reference}$
    7173                        & const ccr = cx;
    72 // pointer
     74\end{cfa}
     75\begin{cquote}
     76\setlength{\tabcolsep}{26pt}
     77\begin{tabular}{@{}lll@{}}
     78pointer & reference & \\
     79\begin{cfa}
    7380*cp = 7;
    74 cp = &x; $\C{// error, assignment of read-only variable}$
    75 *ccp = 7; $\C{// error, assignment of read-only location}$
    76 ccp = &cx; $\C{// error, assignment of read-only variable}$
    77 // reference
     81cp = &x;
     82*ccp = 7;
     83ccp = &cx;
     84\end{cfa}
     85&
     86\begin{cfa}
    7887cr = 7;
    79 cr = &x; $\C{// error, assignment of read-only variable}$
    80 *ccr = 7; $\C{// error, assignment of read-only location}$
    81 ccr = &cx; $\C{// error, assignment of read-only variable}$
    82 \end{cfa}
     88cr = &x;
     89*ccr = 7;
     90ccr = &cx;
     91\end{cfa}
     92&
     93\begin{cfa}
     94// allowed
     95// error, assignment of read-only variable
     96// error, assignment of read-only location
     97// error, assignment of read-only variable
     98\end{cfa}
     99\end{tabular}
     100\end{cquote}
    83101Interestingly, C does not give a warning/error if a @const@ pointer is not initialized, while \CC does.
    84 Hence, type @& const@ is similar to \CC reference, but \CFA does not preclude initialization with a non-variable address.
     102Hence, type @& const@ is similar to a \CC reference, but \CFA does not preclude initialization with a non-variable address.
    85103For example, in system's programming, there are cases where an immutable address is initialized to a specific memory location.
    86104\begin{cfa}
     
    96114However, there is an inherent ambiguity for auto-dereferencing: every argument expression involving a reference variable can potentially mean passing the reference's value or address.
    97115Without any restrictions, this ambiguity limits the behaviour of reference types in \CFA polymorphic functions, where a type @T@ can bind to a reference or non-reference type.
    98 This ambiguity prevents the type system treating reference types the same way as other types in many cases even if type variables could be bound to reference types.
     116This ambiguity prevents the type system treating reference types the same way as other types, even if type variables could be bound to reference types.
    99117The reason is that \CFA uses a common \emph{object trait}\label{p:objecttrait} (constructor, destructor and assignment operators) to handle passing dynamic concrete type arguments into polymorphic functions, and the reference types are handled differently in these contexts so they do not satisfy this common interface.
    100118
    101119Moreover, there is also some discrepancy in how the reference types are treated in initialization and assignment expressions.
    102 For example, in line 3 of the previous example code \see{\VPageref{p:refexamples}}:
     120For example, in line 3 of the example code on \VPageref{p:refexamples}:
    103121\begin{cfa}
    104122int @&@ r1 = x,  @&&@ r2 = r1,   @&&&@ r3 = r2; $\C{// references to x}$
     
    129147vector( int @&@ ) vec; $\C{// vector of references to ints}$
    130148\end{cfa}
    131 While it is possible to write a reference type as the argument to a generic type, it is disallowed in assertion checking, if the generic type requires the object trait \see{\VPageref{p:objecttrait}} for the type argument (a fairly common use case).
     149While it is possible to write a reference type as the argument to a generic type, it is disallowed in assertion checking, if the generic type requires the object trait \see{\VPageref{p:objecttrait}} for the type argument, a fairly common use case.
    132150Even if the object trait can be made optional, the current type system often misbehaves by adding undesirable auto-dereference on the referenced-to value rather than the reference variable itself, as intended.
    133151Some tweaks are necessary to accommodate reference types in polymorphic contexts and it is unclear what can or cannot be achieved.
    134 Currently, there are contexts where \CFA programmer must use pointer types, giving up the benefits of auto-dereference operations and better syntax with reference types.
     152Currently, there are contexts where \CFA programmer is forced to use a pointer type, giving up the benefits of auto-dereference operations and better syntax with reference types.
    135153
    136154
     
    165183Along with making returning multiple values a first-class feature, tuples were extended to simplify a number of other common context that normally require multiple statements and/or additional declarations, all of which reduces coding time and errors.
    166184\begin{cfa}
    167 [x, y, z] = 3; $\C[2in]{// x = 3; y = 3; z = 3, where types are different}$
     185[x, y, z] = 3; $\C[2in]{// x = 3; y = 3; z = 3, where types may be different}$
    168186[x, y] = [y, x]; $\C{// int tmp = x; x = y; y = tmp;}$
    169187void bar( int, int, int );
     
    212230bar( t2 );                      $\C{// bar defined above}$
    213231\end{cfa}
    214 \VRef[Figure]{f:Nesting} shows The difference is nesting of structures and tuples.
     232\VRef[Figure]{f:Nesting} shows the difference is nesting of structures and tuples.
    215233The left \CC nested-structure is named so it is not flattened.
    216234The middle C/\CC nested-structure is unnamed and flattened, causing an error because @i@ and @j@ are duplication names.
     
    220238
    221239\begin{figure}
    222 \setlength{\tabcolsep}{15pt}
     240\setlength{\tabcolsep}{20pt}
    223241\begin{tabular}{@{}ll@{\hspace{90pt}}l@{}}
    224242\multicolumn{1}{c}{\CC} & \multicolumn{1}{c}{C/\CC} & \multicolumn{1}{c}{tuple} \\
     
    273291As noted, tradition languages manipulate multiple values by in/out parameters and/or structures.
    274292K-W C adopted the structure for tuple values or variables, and as needed, the fields are extracted by field access operations.
    275 As well, For the tuple-assignment implementation, the left-hand tuple expression is expanded into assignments of each component, creating temporary variables to avoid unexpected side effects.
    276 For example, the tuple value returned from @foo@ is a structure, and its fields are individually assigned to a left-hand tuple, @x@, @y@, @z@, or copied directly into a corresponding tuple variable.
     293As well, for the tuple-assignment implementation, the left-hand tuple expression is expanded into assignments of each component, creating temporary variables to avoid unexpected side effects.
     294For example, the tuple value returned from @foo@ is a structure, and its fields are individually assigned to a left-hand tuple, @x@, @y@, @z@, \emph{or} copied directly into a corresponding tuple variable.
    277295
    278296In the second implementation of \CFA tuples by Rodolfo Gabriel Esteves~\cite{Esteves04}, a different strategy is taken to handle MVR functions.
     
    286304[x, y] = gives_two();
    287305\end{cfa}
    288 The Till K-W C implementation translates the program to:
     306\VRef[Figure]{f:AlternateTupleImplementation} shows the two implementation approaches.
     307In the left approach, the return statement is rewritten to pack the return values into a structure, which is returned by value, and the structure fields are indiviually assigned to the left-hand side of the assignment.
     308In the right approach, the return statement is rewritten as direct assignments into the passed-in argument addresses.
     309The right imlementation looks more concise and saves unnecessary copying.
     310The downside is indirection within @gives_two@ to access values, unless values get hoisted into registers for some period of time, which is common.
     311
     312\begin{figure}
     313\begin{cquote}
     314\setlength{\tabcolsep}{20pt}
     315\begin{tabular}{@{}ll@{}}
     316Till K-W C implementation & Rodolfo \CFA implementation \\
    289317\begin{cfa}
    290318struct _tuple2 { int _0; int _1; }
    291 struct _tuple2 gives_two() { ... struct _tuple2 ret = { r1, r2 }, return ret; }
     319struct _tuple2 gives_two() {
     320        ... struct _tuple2 ret = { r1, r2 };
     321        return ret;
     322}
    292323int x, y;
    293324struct _tuple2 _tmp = gives_two();
    294325x = _tmp._0; y = _tmp._1;
    295326\end{cfa}
    296 while the Rodolfo implementation translates it to:
    297 \begin{cfa}
    298 void gives_two( int * r1, int * r2 ) { ... *r1 = ...; *r2 = ...; return; }
     327&
     328\begin{cfa}
     329
     330void gives_two( int * r1, int * r2 ) {
     331        ... *r1 = ...; *r2 = ...;
     332        return;
     333}
    299334int x, y;
     335
    300336gives_two( &x, &y );
    301337\end{cfa}
    302 and inside the body of the function @gives_two@, the return statement is rewritten as assignments into the passed-in argument addresses.
    303 This implementation looks more concise, and in the case of returning values having nontrivial types, \eg aggregates, this implementation saves unnecessary copying.
    304 For example,
    305 \begin{cfa}
    306 [ x, y ] gives_two();
    307 int x, y;
    308 [ x, y ] = gives_two();
    309 \end{cfa}
    310 becomes
    311 \begin{cfa}
    312 void gives_two( int &, int & );
    313 int x, y;
    314 gives_two( x, y );
    315 \end{cfa}
    316 eliminiating any copying in or out of the call.
    317 The downside is indirection within @gives_two@ to access values, unless values get hoisted into registers for some period of time, which is common.
     338\end{tabular}
     339\end{cquote}
     340\caption{Alternate Tuple Implementation}
     341\label{f:AlternateTupleImplementation}
     342\end{figure}
    318343
    319344Interestingly, in the third implementation of \CFA tuples by Robert Schluntz~\cite[\S~3]{Schluntz17}, the MVR functions revert back to structure based, where it remains in the current version of \CFA.
    320345The reason for the reversion was to have a uniform approach for tuple values/variables making tuples first-class types in \CFA, \ie allow tuples with corresponding tuple variables.
    321 This extension was possible, because in parallel with Schluntz's work, generic types were being added independently by Moss~\cite{Moss19}, and the tuple variables leveraged the same implementation techniques as the generic variables.
     346This extension was possible, because in parallel with Schluntz's work, generic types were added independently by Moss~\cite{Moss19}, and the tuple variables leveraged the same implementation techniques as the generic variables.
    322347\PAB{I'm not sure about the connection here. Do you have an example of what you mean?}
    323348
     
    339364\begin{cfa}
    340365void f( int, int );
    341 void f( [int, int] );
     366void f( @[@ int, int @]@ );
    342367f( 3, 4 );  // ambiguous call
    343368\end{cfa}
     
    358383the call to @f@ can be interpreted as @T = [1]@ and @U = [2, 3, 4, 5]@, or @T = [1, 2]@ and @U = [3, 4, 5]@, and so on.
    359384The restriction ensures type checking remains tractable and does not take too long to compute.
    360 Therefore, tuple types are never present in any fixed-argument function calls.
    361 
    362 Finally, a type-safe variadic argument signature was added by Robert Schluntz~\cite[\S~4.1.2]{Schluntz17} using @forall@ and a new tuple parameter-type, denoted by the keyword @ttype @ in Schluntz's implementation, but changed to the ellipsis syntax similar to \CC's template parameter pack.
     385Therefore, tuple types are never present in any fixed-argument function calls, because of the flattening.
     386
     387Finally, a type-safe variadic argument signature was added by Robert Schluntz~\cite[\S~4.1.2]{Schluntz17} using @forall@ and a new tuple parameter-type, denoted by the keyword @ttype@ in Schluntz's implementation, but changed to the ellipsis syntax similar to \CC's template parameter pack.
    363388For C variadics, \eg @va_list@, the number and types of the arguments must be conveyed in some way, \eg @printf@ uses a format string indicating the number and types of the arguments.
    364389\VRef[Figure]{f:CVariadicMaxFunction} shows an $N$ argument @maxd@ function using the C untyped @va_list@ interface.
     
    370395\begin{figure}
    371396\begin{cfa}
    372 double maxd( int @count@, ... ) {
     397double maxd( int @count@, @...@ ) { // ellipse parameter
    373398    double max = 0;
    374399    va_list args;
     
    566591struct U u;  u.k;  u.l;
    567592\end{cfa}
    568 and the hoisted type names can clash with global types names.
     593and the hoisted type names can clash with global type names.
    569594For good reasons, \CC chose to change this semantics:
    570595\begin{cquote}
     
    584609\end{cfa}
    585610\CFA chose to adopt the \CC non-compatible change for nested types, since \CC's change has already forced certain coding changes in C libraries that must be parsed by \CC.
     611\CFA also added the ability to access from a variable through a type to a field.
     612\begin{cfa}
     613struct S s;  @s.T@.i;  @s.U@.k;
     614\end{cfa}
    586615
    587616% https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html
     
    604633\end{cfa}
    605634Note, the position of the substructure is normally unimportant, unless there is some form of memory or @union@ overlay.
    606 Like the anonymous nested types, the aggregate field names are hoisted into @struct S@, so there is direct access, \eg @s.x@ and @s.i@.
    607 However, like the implicit C hoisting of nested structures, the field names must be unique and the type names are now at a different scope level, unlike type nesting in \CC.
    608 In addition, a pointer to a structure is automatically converted to a pointer to an anonymous field for assignments and function calls, providing containment inheritance with implicit subtyping, \ie @U@ $\subset$ @S@ and @W@ $\subset$ @S@.
    609 For example:
     635Like an anonymous nested type, a named nested Plan-9 type has its field names hoisted into @struct S@, so there is direct access, \eg @s.x@ and @s.i@.
     636Hence, the field names must be unique, unlike \CC nested types, but the type names are at a nested scope level, unlike type nesting in C.
     637In addition, a pointer to a structure is automatically converted to a pointer to an anonymous field for assignments and function calls, providing containment inheritance with implicit subtyping, \ie @U@ $\subset$ @S@ and @W@ $\subset$ @S@, \eg:
    610638\begin{cfa}
    611639void f( union U * u );
    612640void g( struct W * );
    613 union U * up;
    614 struct W * wp;
    615 struct S * sp;
    616 up = sp; $\C{// assign pointer to U in S}$
    617 wp = sp; $\C{// assign pointer to W in S}$
     641union U * up;   struct W * wp;   struct S * sp;
     642up = &s; $\C{// assign pointer to U in S}$
     643wp = &s; $\C{// assign pointer to W in S}$
    618644f( &s ); $\C{// pass pointer to U in S}$
    619645g( &s ); $\C{// pass pointer to W in S}$
    620646\end{cfa}
    621 
    622 \CFA extends the Plan-9 substructure by allowing polymorphism for values and pointers.
    623 The extended substructure is denoted using @inline@, allowing backwards compatibility to existing Plan-9 features.
     647Note, there is no value assignment, such as, @w = s@, to copy the @W@ field from @S@.
     648
     649Unfortunately, the Plan-9 designers did not lookahead to other useful features, specifically nested types.
     650This nested type compiles in \CC and \CFA.
     651\begin{cfa}
     652struct R {
     653        @struct T;@             $\C[2in]{// forward declaration, conflicts with Plan-9 syntax}$
     654        struct S {              $\C{// nested types, mutually recursive reference}\CRT$
     655                S * sp;   T * tp;  ...
     656        };
     657        struct T {
     658                S * sp;   T * tp;  ...
     659        };
     660};
     661\end{cfa}
     662Note, the syntax for the forward declaration conflicts with the Plan-9 declaration syntax.
     663
     664\CFA extends the Plan-9 substructure by allowing polymorphism for values and pointers, where the extended substructure is denoted using @inline@.
    624665\begin{cfa}
    625666struct S {
    626         @inline@ W;  $\C{// extended Plan-9 substructure}$
     667        @inline@ struct W;  $\C{// extended Plan-9 substructure}$
    627668        unsigned int tag;
    628669        @inline@ U;  $\C{// extended Plan-9 substructure}$
    629670} s;
    630671\end{cfa}
    631 Note, like \CC, \CFA allows optional prefixing of type names with their kind, \eg @struct@, @union@, and @enum@, unless there is ambiguity with variable names in the same scope.
    632 The following shows both value and pointer polymorphism.
     672Note, the declaration of @U@ is not prefixed with @union@.
     673Like \CC, \CFA allows optional prefixing of type names with their kind, \eg @struct@, @union@, and @enum@, unless there is ambiguity with variable names in the same scope.
     674In addition, a semi-non-compatible change is made so that Plan-9 syntax means a forward declaration in a nested type.
     675Since the Plan-9 extension is not part of C and rarely used, this change has minimal impact.
     676Hence, all Plan-9 semantics are denoted by the @inline@ qualifier, which good ``eye-candy'' when reading a structure definition to spot Plan-9 definitions.
     677Finally, the following code shows the value and pointer polymorphism.
    633678\begin{cfa}
    634679void f( U, U * ); $\C{// value, pointer}$
    635680void g( W, W * ); $\C{// value, pointer}$
    636 U u, * up;
    637 S s, * sp;
    638 W w, * wp;
    639 u = s;  up = sp; $\C{// value, pointer}$
    640 w = s;  wp = sp; $\C{// value, pointer}$
     681U u, * up;   S s, * sp;   W w, * wp;
     682u = s;   up = sp; $\C{// value, pointer}$
     683w = s;   wp = sp; $\C{// value, pointer}$
    641684f( s, &s ); $\C{// value, pointer}$
    642685g( s, &s ); $\C{// value, pointer}$
     
    645688In general, non-standard C features (@gcc@) do not need any special treatment, as they are directly passed through to the C compiler.
    646689However, the Plan-9 semantics allow implicit conversions from the outer type to the inner type, which means the \CFA type resolver must take this information into account.
    647 Therefore, the \CFA translator must implement the Plan-9 features and insert necessary type conversions into the translated code output.
     690Therefore, the \CFA resolver must implement the Plan-9 features and insert necessary type conversions into the translated code output.
    648691In the current version of \CFA, this is the only kind of implicit type conversion other than the standard C conversions.
    649692
    650 Since variable overloading is possible in \CFA, \CFA's implementation of Plan-9 polymorphism allows duplicate field names.
    651 When an outer field and an embedded field have the same name and type, the inner field is shadowed and cannot be accessed directly by name.
    652 While such definitions are allowed, duplicate field names is not good practice in general and should be avoided if possible.
    653 Plan-9 fields can be nested, and a struct definition can contain multiple Plan-9 embedded fields.
    654 In particular, the \newterm{diamond pattern}~\cite[\S~6.1]{Stroustrup89}\cite[\S~4]{Cargill91}  can occur and result in a nested field to be embedded twice.
     693Plan-9 polymorphism can result in duplicate field names.
     694For example, the \newterm{diamond pattern}~\cite[\S~6.1]{Stroustrup89}\cite[\S~4]{Cargill91} can result in nested fields being embedded twice.
    655695\begin{cfa}
    656696struct A { int x; };
     
    658698struct C { inline A; };
    659699struct D {
    660         inline B;
    661         inline C;
    662 };
    663 D d;
    664 \end{cfa}
    665 In the above example, the expression @d.x@ becomes ambiguous, since it can refer to the indirectly embedded field either from @B@ or from @C@.
    666 It is still possible to disambiguate the expression by first casting the outer struct to one of the directly embedded type, such as @((B)d).x@.
     700        inline B;  // B.x
     701        inline C;  // C.x
     702} d;
     703\end{cfa}
     704Because the @inline@ structures are flattened, the expression @d.x@ is ambiguous, as it can refer to the embedded field either from @B@ or @C@.
     705@gcc@ generates a syntax error about the duplicate member @x@.
     706The equivalent \CC definition compiles:
     707\begin{c++}
     708struct A { int x; };
     709struct B : public A {};
     710struct C : public A {};
     711struct D : @public B, C@ {  // multiple inheritance
     712} d;
     713\end{c++}
     714and again the expression @d.x@ is ambiguous.
     715While \CC has no direct syntax to disambiguate @x@, \ie @d.B.x@ or @d.C.x@, it is possible with casts, @((B)d).x@ or @((C)d).x@.
     716Like \CC, \CFA compiles the Plan-9 version and provides direct syntax and casts to disambiguate @x@.
     717While ambiguous definitions are allowed, duplicate field names is poor practice and should be avoided if possible.
     718However, when a programmer does not control all code, this problem can occur and a naming workaround should exist.
  • doc/theses/mike_brooks_MMath/Makefile

    rb006c51e r10a9479d  
    1010TeXSRC = ${wildcard *.tex}
    1111PicSRC = ${notdir ${wildcard ${Pictures}/*.png}}
    12 DemoSRC = ${notdir ${wildcard ${Programs}/*-demo.cfa}}
     12DemoPgmSRC = ${notdir ${wildcard ${Programs}/*-demo.cfa}}
    1313PgmSRC = ${notdir ${wildcard ${Programs}/*}}
    1414RunPgmSRC = ${notdir ${wildcard ${Programs}/*.run.*}}
     
    2424BASE = ${basename ${DOCUMENT}}                  # remove suffix
    2525
    26 DemoTex = ${DemoSRC:%.cfa=${Build}/%.tex}
    2726RunPgmExe = ${addprefix ${Build}/,${basename ${basename ${RunPgmSRC}}}}
    2827RunPgmOut = ${RunPgmExe:%=%.out}
     28DemoPgmExe = ${addprefix ${Build}/,${basename ${basename ${DemoPgmSRC}}}}
     29DemoPgmOut = ${DemoPgmExe:%=%.out}
    2930
    3031# Commands
     
    3839# Rules and Recipes
    3940
    40 .PHONY : all fragments_ran clean                        # not file names
    41 .PRECIOUS : ${Build}/% ${Build}/%-demo      # don't delete intermediates
     41.PHONY : all clean                              # not file names
     42.SECONDARY:
     43#.PRECIOUS : ${Build}/%                         # don't delete intermediates
    4244.ONESHELL :
    4345
    44 all : fragments_ran ${DOCUMENT}
    45 
    46 fragments_ran : $(RunPgmOut)
     46all : ${DOCUMENT}
    4747
    4848clean :
     
    5151# File Dependencies
    5252
    53 %.pdf : ${TeXSRC} ${DemoTex} ${PicSRC} ${PgmSRC} ${BibSRC} ${BibRep}/pl.bib ${LaTMac}/common.tex Makefile | ${Build}
     53%.pdf : ${TeXSRC} $(RunPgmOut) ${DemoPgmOut} ${PicSRC} ${BibSRC} ${BibRep}/pl.bib ${LaTMac}/common.tex Makefile | ${Build}
    5454        ${LaTeX} ${BASE}
    5555        ${BibTeX} ${Build}/${BASE}
     
    6464        mkdir -p $@
    6565
    66 %-demo.tex: %-demo | ${Build}
    67         $< > $@
     66${Build}/%-demo: ${Programs}/%-demo.cfa | ${Build}
     67        ${CFA} $< -o $@
    6868
    69 ${Build}/%-demo: ${Programs}/%-demo.cfa | ${Build}
     69${Build}/%: ${Programs}/%-demo.cfa | ${Build}
    7070        ${CFA} $< -o $@
    7171
  • doc/theses/mike_brooks_MMath/array.tex

    rb006c51e r10a9479d  
    22\label{c:Array}
    33
     4Arrays in C are possibly the single most misunderstood and incorrectly used feature in the language, resulting in the largest proportion of runtime errors and security violations.
     5This chapter describes the new \CFA language and library features that introduce a length-checked array type, @array@, to the \CFA standard library~\cite{Cforall}.
     6
     7Offering the @array@ type, as a distinct alternative to the C array, is consistent with \CFA's goal of backwards compatibility, \ie virtually all existing C (@gcc@) programs can be compiled by \CFA with only a small number of changes, similar to \CC (@g++@).
     8However, a few compatibility-breaking changes to the behaviour of the C array are necessary, both as an implementation convenience and to fix C's lax treatment of arrays.
     9Hence, the @array@ type is an opportunity to start from a clean slate and show a cohesive selection of features, making it unnecessary to deal with every inherited complexity of the C array.
     10
    411
    512\section{Introduction}
    613\label{s:ArrayIntro}
    714
    8 Arrays in C are possibly the single most misunderstood and incorrectly used feature in the language, resulting in the largest proportion of runtime errors and security violations.
    9 This chapter describes the new \CFA language and library features that introduce a length-checked array type to the \CFA standard library~\cite{Cforall}.
    10 
    11 Specifically, a new \CFA array is declared by instantiating the generic @array@ type,
    12 much like instantiating any other standard-library generic type (such as @dlist@),
     15The new \CFA array is declared by instantiating the generic @array@ type,
     16much like instantiating any other standard-library generic type (such as \CC @vector@),
    1317though using a new style of generic parameter.
    1418\begin{cfa}
     
    1620\end{cfa}
    1721Here, the arguments to the @array@ type are @float@ (element type) and @99@ (length).
    18 When this type is used as a function parameter, the type-system requires that a call's argument matches, down to the length.
     22When this type is used as a function parameter, the type-system requires that a call's argument is a perfect match.
    1923\begin{cfa}
    2024void f( @array( float, 42 )@ & p ) {}   $\C{// p accepts 42 floats}$
    21 f( x );                                                                 $\C{// statically rejected: types are different, 99 != 42}$
     25f( x );                                                                 $\C{// statically rejected: type lengths are different, 99 != 42}$
    2226
    2327test2.cfa:3:1 error: Invalid application of existing declaration(s) in expression.
     
    2529\end{cfa}
    2630Here, the function @f@'s parameter @p@ is declared with length 42.
    27 The call @f( x )@, with the argument being the previously-declared object, is invalid, because the @array@ lengths @99@ and @42@ do not match.
    28 
    29 A function declaration can be polymorphic over these @array@ arguments by using the @forall@ declaration prefix.
    30 This function @g@'s takes arbitrary type parameter @T@ (familiar) and \emph{dimension parameter} @N@ (new).
    31 A dimension paramter represents a to-be-determined count of elements, managed by the type system.
     31However, the call @f( x )@ is invalid, because @x@'s length is @99@, which does not match @42@.
     32
     33A function declaration can be polymorphic over these @array@ arguments by using the \CFA @forall@ declaration prefix.
    3234\begin{cfa}
    3335forall( T, @[N]@ )
     
    4042Cforall Runtime error: subscript 1000 exceeds dimension range [0,99) $for$ array 0x555555558020.
    4143\end{cfa}
     44Function @g@ takes an arbitrary type parameter @T@ and a \emph{dimension parameter} @N@.
     45A dimension parameter represents a to-be-determined count of elements, managed by the type system.
    4246The call @g( x, 0 )@ is valid because @g@ accepts any length of array, where the type system infers @float@ for @T@ and length @99@ for @N@.
    43 Inferring values for @T@ and @N@ is implicit, without programmer involvement.
     47Inferring values for @T@ and @N@ is implicit.
    4448Furthermore, in this case, the runtime subscript @x[0]@ (parameter @i@ being @0@) in @g@ is valid because 0 is in the dimension range $[0,99)$ of argument @x@.
    45 The call @g( x, 1000 )@ is also accepted through compile time;
     49However, the call @g( x, 1000 )@ is also accepted through compile time;
    4650however, this case's subscript, @x[1000]@, generates an error, because @1000@ is outside the dimension range $[0,99)$ of argument @x@.
     51In general, the @forall( ..., [N] )@ participates in the user-relevant declaration of the name @N@, which becomes usable in parameter/return declarations and within a function.
     52The syntactic form is chosen to parallel other @forall@ forms:
     53\begin{cfa}
     54forall( @[N]@ ) ...     $\C[1.5in]{// dimension}$
     55forall( T ) ...         $\C{// value datatype (formerly, "otype")}$
     56forall( T & ) ...       $\C{// opaque datatype (formerly, "dtype")}\CRT$
     57\end{cfa}
     58% The notation @array(thing, N)@ is a single-dimensional case, giving a generic type instance.
    4759
    4860The generic @array@ type is comparable to the C array type, which \CFA inherits from C.
    4961Their runtime characteristics are often identical, and some features are available in both.
    50 For example, assume a caller instantiates @N@ with 42 (discussion about how to follow) in:
     62For example, assume a caller has an argument that instantiates @N@ with 42.
    5163\begin{cfa}
    5264forall( [N] )
    53 void declDemo() {
     65void declDemo( ... ) {
    5466        float x1[N];                                            $\C{// built-in type ("C array")}$
    5567        array(float, N) x2;                                     $\C{// type from library}$
     
    5971The two variables have identical size and layout; they both encapsulate 42-float stack allocations, with no additional ``bookkeeping'' allocations or headers.
    6072Providing this explicit generic approach requires a significant extension to the \CFA type system to support a full-feature, safe, efficient (space and time) array-type, which forms the foundation for more complex array forms in \CFA.
    61 
    62 Admittedly, the @array@ library type (type for @x2@) is syntactically different from its C counterpart.
    63 A future goal (TODO xref) is to provide the new features upon a built-in type whose syntax approaches C's (declaration style of @x1@).
     73In all following discussion, ``C array'' means the types like that of @x@ and ``\CFA array'' means the standard-library @array@ type (instantiations), like the type of @x2@.
     74
     75Admittedly, the @array@ library type for @x2@ is syntactically different from its C counterpart.
     76A future goal (TODO xref) is to provide the new @array@ features with syntax approaching C's (declaration style of @x1@).
    6477Then, the library @array@ type could be removed, giving \CFA a largely uniform array type.
    65 At present, the C-syntax array gets partial support for the new features, so the generic @array@ is used exclusively when introducing features;
     78At present, the C-syntax @array@ is only partially supported, so the generic @array@ is used exclusively in the thesis;
    6679feature support and C compatibility are revisited in Section ? TODO.
    67 
    68 Offering the @array@ type, as a distinct alternative to the C array, is consistent with \CFA's goal of backwards compatibility, \ie virtually all existing C (@gcc@) programs can be compiled by \CFA with only a small number of changes, similar to \CC (@g++@).
    69 However, a few compatibility-breaking changes to the behaviour of the C array are necessary, both as an implementation convenience and to fix C's lax treatment of arrays.
    70 Hence, the @array@ type is an opportunity to start from a clean slate and show a cohesive selection of features, making it unnecessary to deal with every inherited complexity of the C array.
    71 
    72 In all discussion following, ``C array'' means the types like that of @x@ and ``\CFA array'' means the standard-library @array@ type (instantiations), like the type of @x2@.
    7380
    7481My contributions in this chapter are:
     
    8390
    8491
    85 \section{Definitions and design considerations}
    86 
    87 
    88 \subsection{Dependent typing}
    89 
    90 
    91 
    92 General dependent typing allows the type system to encode arbitrary predicates (e.g. behavioural specifications for functions),
     92\section{Dependent typing}
     93
     94General dependent typing allows the type system to encode arbitrary predicates (\eg behavioural specifications for functions),
    9395which is an anti-goal for my work.
    9496Firstly, this application is strongly associated with pure functional languages,
     
    101103
    102104
    103 
    104105\section{Features added}
    105106
     
    109110By declaring type variables at the front of object declarations, an array dimension is lexically referenceable where it is needed.
    110111For example, a declaration can share one length, @N@, among a pair of parameters and the return,
    111 meaning that it requires both input arrays to be of the same length, and guarantees that the result with be of that length as well.
     112meaning that it requires both input arrays to be of the same length, and guarantees that the result is of that length as well.
    112113\lstinput{10-17}{hello-array.cfa}
    113 This function @f@ does a pointwise comparison of its two input arrays, checking if each pair of numbers is within half a percent of each other, returning the answers in a newly allocated @bool@ array.
    114 The dynamic allocation of the @ret@ array by preexisting @alloc@ uses the parameterized dimension information implicitly within its @sizeof@ determination, and casts the return type.
    115 Note that alloc only sees one whole type for its @T@ (which is @f@'s @array(bool, N)@); this type's size is a computation based on @N@.
    116 \begin{cfa}
    117 // simplification
    118 static inline forall( T & | sized(T) )
     114Function @f@ does a pointwise comparison of its two input arrays, checking if each pair of numbers is within half a percent of each other, returning the answers in a newly allocated @bool@ array.
     115The dynamic allocation of the @ret@ array, by the library @alloc@ function,
     116\begin{cfa}
     117forall( T & | sized(T) )
    119118T * alloc() {
    120         return (T *)malloc( sizeof(T) );
    121 }
    122 \end{cfa}
    123 This example illustrates how the new @array@ type plugs into existing \CFA behaviour by implementing necessary @sized@ assertions needed by other types.
    124 (@sized@ implies a concrete \vs abstract type with a runtime-available size, exposed as @sizeof@.)
     119        return @(T *)@malloc( @sizeof(T)@ );
     120}
     121\end{cfa}
     122uses the parameterized dimension information implicitly within its @sizeof@ determination, and casts the return type.
     123Note that @alloc@ only sees one whole type for its @T@ (which is @f@'s @array(bool, N)@); this type's size is a computation based on @N@.
     124This example illustrates how the new @array@ type plugs into existing \CFA behaviour by implementing necessary \emph{sized} assertions needed by other types.
     125(\emph{sized} implies a concrete \vs abstract type with a runtime-available size, exposed as @sizeof@.)
    125126As a result, there is significant programming safety by making the size accessible and implicit, compared with C's @calloc@ and non-array supporting @memalign@, which take an explicit length parameter not managed by the type system.
    126127
     
    142143The result is a significant improvement in safety and usability.
    143144
    144 In general, the @forall( ..., [N] )@ participates in the user-relevant declaration of the name @N@, which becomes usable in parameter/return declarations and within a function.
    145 The syntactic form is chosen to parallel other @forall@ forms:
    146 \begin{cfa}
    147 forall( @[N]@ ) ...     $\C[1.5in]{// dimension}$
    148 forall( T & ) ...       $\C{// opaque datatype (formerly, "dtype")}$
    149 forall( T ) ...         $\C{// value datatype (formerly, "otype")}\CRT$
    150 \end{cfa}
    151 % The notation @array(thing, N)@ is a single-dimensional case, giving a generic type instance.
    152145In summary:
    153146\begin{itemize}
     
    168161% agreed, though already said
    169162\item
    170 \CC does not allow a template function to be nested, while \CFA lests its polymorphic functions to be nested.
     163\CC does not allow a template function to be nested, while \CFA lets its polymorphic functions to be nested.
    171164% why is this important?
    172165\item
     
    227220\end{cfa}
    228221\end{tabular}
    229 \caption{\lstinline{N}-style paramters, for \CC template \vs \CFA generic type }
     222\caption{\lstinline{N}-style parameters, for \CC template \vs \CFA generic type }
    230223\label{f:TemplateVsGenericType}
    231224\end{figure}
    232225
    233226Just as the first example in \VRef[Section]{s:ArrayIntro} shows a compile-time rejection of a length mismatch,
    234 so are length mismatches stopped when they invlove dimension parameters.
     227so are length mismatches stopped when they involve dimension parameters.
    235228While \VRef[Figure]{f:fHarness} shows successfully calling a function @f@ expecting two arrays of the same length,
    236229\begin{cfa}
    237230array( bool, N ) & f( array( float, N ) &, array( float, N ) & );
    238231\end{cfa}
    239 a static rejection occurs when attempting to call @f@ with arrays of potentially differing lengths.
     232a static rejection occurs when attempting to call @f@ with arrays of differing lengths.
    240233\lstinput[tabsize=1]{70-74}{hello-array.cfa}
    241234When the argument lengths themselves are statically unknown,
     
    252245Orthogonally, the \CFA array type works within generic \emph{types}, \ie @forall@-on-@struct@.
    253246The same argument safety and the associated implicit communication of array length occurs.
    254 Preexisting \CFA allowed aggregate types to be generalized with type parameters, enabling parameterizing for element types.
     247Preexisting \CFA allowed aggregate types to be generalized with type parameters, enabling parameterizing of element types.
    255248Now, \CFA also allows parameterizing them by length.
    256249Doing so gives a refinement of C's ``flexible array member'' pattern[TODO: cite ARM 6.7.2.1 pp18]\cite{arr:gnu-flex-mbr}.
     
    259252This flexibility, in turn, allows for multiple array members.
    260253\lstinput{10-15}{hello-accordion.cfa}
    261 This structure's layout has the starting offset of @studentIds@ varying according to the generic parameter @C@, and the offset of @preferences@ varying according to both generic parameters.
    262 
    263 The school example has the data structure capturing many students' course-preference forms.
    264 It has course- and student-level metadata (their respective display names) and a position-based preferecens' matrix.
    265 The input files in \VRef[Figure]{f:checkHarness} give example data.
    266 
    267 When a function operates on a @School@ structure, the type system handles its memory layout transparently.
    268 \lstinput{30-37}{hello-accordion.cfa}
    269 In the running example, this @getPref@ function answers,
    270 for the student at position @sIx@, what is the position of its @pref@\textsuperscript{th}-favoured class?
    271 
    272 \VRef[Figure]{f:checkHarness} shows the @School@ harness and results with different array sizes.
    273 This example program prints the courses in each student's preferred order, all using the looked-up display names.
    274 Note the declaration of the @school@ variable.
     254The structure has course- and student-level metatdata (their respective field names) and a position-based preferences' matrix.
     255Its layout has the starting offset of @studentIds@ varying according to the generic parameter @C@, and the offset of @preferences@ varying according to both generic parameters.
     256
     257\VRef[Figure]{f:checkHarness} shows a program main using @School@ and results with different array sizes.
     258The @school@ variable holds many students' course-preference forms.
    275259It is on the stack and its initialization does not use any casting or size arithmetic.
    276260Both of these points are impossible with a C flexible array member.
     
    280264\end{cfa}
    281265This ability to avoid casting and size arithmetic improves safety and usability over C flexible array members.
    282 
     266Finally, inputs and outputs are given at the bottom for different sized schools.
     267The example program prints the courses in each student's preferred order, all using the looked-up display names.
    283268
    284269\begin{figure}
    285 % super hack to get this to line up
    286 \begin{tabular}{@{}ll@{\hspace{25pt}}l@{}}
    287 \begin{tabular}{@{}p{3.25in}@{}}
     270\begin{cquote}
    288271\lstinput{50-55}{hello-accordion.cfa}
    289 \vspace*{-3pt}
    290272\lstinput{90-98}{hello-accordion.cfa}
    291 \end{tabular}
    292 &
    293 \raisebox{0.32\totalheight}{%
    294 }%
    295 &
    296 \end{tabular}
    297 
    298 TODO: Get Peter's layout help
    299 
    300 \$ cat school1
    301 
     273\ \\
     274@$ cat school1@
    302275\lstinput{}{school1}
    303276
    304 \$ ./a.out < school1
    305 
     277@$ ./a.out < school1@
    306278\lstinput{}{school1.out}
    307279
    308 \$ cat school2
    309 
     280@$ cat school2@
    310281\lstinput{}{school2}
    311282
    312 \$ ./a.out < school2
    313 
     283@$ ./a.out < school2@
    314284\lstinput{}{school2.out}
     285\end{cquote}
    315286
    316287\caption{\lstinline{School} harness, input and output}
    317288\label{f:checkHarness}
    318289\end{figure}
     290
     291When a function operates on a @School@ structure, the type system handles its memory layout transparently.
     292\lstinput{30-37}{hello-accordion.cfa}
     293In the example, this @getPref@ function answers, for the student at position @is@, what is the position of its @pref@\textsuperscript{th}-favoured class?
    319294
    320295
     
    333308But simplifications close enough for the present discussion are:
    334309\begin{cfa}
    335         forall( [N] )
    336         struct array_1d_float {
    337                 float items[N];
    338         };
    339         forall( T, [N] )
    340         struct array_1d {
    341                 T items[N];
    342         };
    343 \end{cfa}
    344 This structure pattern, plus a subscript operator, is all that @array@ provides.
     310forall( [N] )
     311struct array_1d_float {
     312        float items[N];
     313};
     314forall( T, [N] )
     315struct array_1d_T {
     316        T items[N];
     317};
     318\end{cfa}
     319These two structure patterns, plus a subscript operator, is all that @array@ provides.
    345320
    346321My main work is letting a programmer define
    347 such a structre (one whose type is parameterized by @[N]@)
     322such a structure (one whose type is parameterized by @[N]@)
    348323and functions that operate on it (these being similarly parameterized).
    349324
     
    351326\begin{itemize}
    352327\item
    353         The resolver, providing values for a used declaration's type-system variables,
     328        Resolver provided values for a used declaration's type-system variables,
    354329        gathered from type information in scope at the usage site.
    355 
    356330\item
    357331        The box pass, encoding information about type parameters
    358332        into ``extra'' regular parameters/arguments on declarations and calls.
    359333        Notably, it conveys the size of a type @foo@ as a @__sizeof_foo@ parameter,
    360         and rewrites the @sizeof(foo)@ expression as @__sizeof_foo@, i.e. a use of the parameter.
     334        and rewrites the @sizeof(foo)@ expression as @__sizeof_foo@, \ie a use of the parameter.
    361335\end{itemize}
    362336
     
    364338This work is detailed in \VRef[Section]{s:ArrayTypingC}.
    365339However, the resolution--boxing scheme, in its preexisting state, was already equipped to work on (desugared) dimension parameters.
    366 The discussion following explains the desugaring and how correct lowered code results.
    367 
    368 An even simpler structure, and a toy function on it, demonstrate what's needed for the encoding.
    369 \begin{cfa}
    370         forall( [@N@] ) { // [1]
    371                 struct thing {};
    372                 void f( thing(@N@) ) { sout | @N@; } // [2], [3]
    373         }
    374         int main() {
    375                 thing( @10@ ) x;  f(x);  // prints 10, [4]
    376                 thing( 100 ) y;  f(y);  // prints 100
    377                 return 0;
    378         }
     340The following discussion explains the desugaring and how correctly lowered code results.
     341
     342A simpler structure, and a toy function on it, demonstrate what is needed for the encoding.
     343\begin{cfa}
     344forall( [@N@] ) { $\C{// [1]}$
     345        struct thing {};
     346        void f( thing(@N@) ) { sout | @N@; } $\C{// [2], [3]}$
     347}
     348int main() {
     349        thing( @10@ ) x;  f( x );  $\C{// prints 10, [4]}$
     350        thing( 100 ) y;  f( y );  $\C{// prints 100}$
     351        return 0;
     352}
    379353\end{cfa}
    380354This example has:
     
    389363        A value like 10 being used as an argument to the parameter @N@.
    390364\end{enumerate}
    391 The chosen solution being to encode the value @N@ \emph{as a type}, items 1 and 2 are immediately available for free.
     365The chosen solution is to encode the value @N@ \emph{as a type}, so items 1 and 2 are immediately available for free.
    392366Item 3 needs a way to recover the encoded value from a (valid) type (and to reject invalid types occurring here).
    393367Item 4 needs a way to produce a type that encodes the given value.
     
    400374\item
    401375        Given a dimension expression $e$, produce type @char[@$e$@]@ to represent it.
    402         If $e$ evaluates to $n$ then the endoded type has size $n$.
     376        If $e$ evaluates to $n$ then the encoded type has size $n$.
    403377\item
    404378        Given a type $T$ (produced by these rules), recover the value that it represents with the expression @sizeof(@$T$@)@.
     
    410384The running example is lowered to:
    411385\begin{cfa}
    412         forall( @N*@ ) { // [1]
    413                 struct thing {};
    414                 void f( thing(@N@) ) { sout | @sizeof(N)@; } // [2], [3]
    415         }
    416         int main() {
    417                 thing( char[@10@] ) x;  f(x);  // prints 10, [4]
    418                 thing( char[100] ) y;  f(y);  // prints 100
    419                 return 0;
    420         }
     386forall( @N *@ ) { $\C{// [1]}$
     387        struct thing {};
     388        void f( thing(@N@) ) { sout | @sizeof(N)@; } $\C{// [2], [3]}$
     389}
     390int main() {
     391        thing( char[@10@] ) x;  f( x );  $\C{// prints 10, [4]}$
     392        thing( char[100] ) y;  f( y );  $\C{// prints 100}$
     393        return 0;
     394}
    421395\end{cfa}
    422396Observe:
     
    430404        The @sout...@ expression (being an application of the @?|?@ operator) has a second argument that is an ordinary expression.
    431405\item
    432         The type of variable @x@ is another @thing(-)@ type;  the argument to the generic @thing@ is a type (array type).
     406        The type of variable @x@ is another @thing(-)@ type; the argument to the generic @thing@ is a type (array type of bytes, @char@).
    433407\end{enumerate}
    434408
    435409From this point, preexisting \CFA compilation takes over lowering it the rest of the way to C.
    436 Inspecting the result shows what the above translation achieves.
    437 A form that shows only the relevant changes of the box pass (as informed by the resolver), leaving the rest unadulterated, is:
    438 \begin{cfa}
    439         // [1]
    440         void f( size_t __sizeof_N, @void *@ ) { sout | @__sizeof_N@; } // [2], [3]
    441         int main() {
    442                 struct __conc_thing_10 {} x;  f(@10@, &x);  // prints 10, [4]
    443                 struct __conc_thing_100 {} y;  f(@100@, &y);  // prints 100
    444                 return 0;
    445         }
     410Here the result shows only the relevant changes of the box pass (as informed by the resolver), leaving the rest unadulterated:
     411\begin{cfa}
     412// [1]
     413void f( size_t __sizeof_N, @void *@ ) { sout | @__sizeof_N@; } $\C{// [2], [3]}$
     414int main() {
     415        struct __conc_thing_10 {} x;  f( @10@, &x );  $\C{// prints 10, [4]}$
     416        struct __conc_thing_100 {} y;  f( @100@, &y );  $\C{// prints 100}$
     417        return 0;
     418}
    446419\end{cfa}
    447420Observe:
     
    452425        The type @thing(N)@ is (replaced by @void *@, but thereby effectively) gone.
    453426\item
    454         The @sout...@ expression (being an application of the @?|?@ operator) has a second argument that is a regular variable (parameter) usage.
     427        The @sout...@ expression (being an application of the @?|?@ operator) has a regular variable (parameter) usage for its second argument.
    455428\item
    456429        Information about the particular @thing@ instantiation (value 10) has moved, from the type, to a regular function-call argument.
    457430\end{enumerate}
    458 At the end of the desugaring and downstream processing, the original C idiom of ``pass both a pointer and a length parameter'' has been reconstructed.
    459 In the programmer-written form, only the thing is passed.
     431At the end of the desugaring and downstream processing, the original C idiom of ``pass both a length parameter and a pointer'' has been reconstructed.
     432In the programmer-written form, only the @thing@ is passed.
    460433The compiler's action produces the more complex form, which if handwritten, would be error-prone.
    461434
    462 Back at the very front end, the parsing changes, AST schema extensions, and validation rules for enabling the sugared user input are:
     435Back at the compiler front end, the parsing changes AST schema extensions and validation rules for enabling the sugared user input.
    463436\begin{itemize}
    464437\item
     
    467440        Have the new brand of type-variable, \emph{Dimension}, in the AST form of a type-variable, to represent one parsed from @[-]@.
    468441\item
    469         Allow a type variable to occur in expression position.  Validate (after parsing) that only dimension-branded type variables are used here.
     442        Allow a type variable to occur in an expression.  Validate (after parsing) that only dimension-branded type variables are used here.
    470443\item
    471444        Allow an expression to occur in type-argument position.  Brand the resulting type argument as a dimension.
     
    473446        Validate (after parsing), on a generic-type usage, \eg the type part of the declaration
    474447        \begin{cfa}
    475                 @array_1d( foo, bar ) x;@
     448        array_1d( foo, bar ) x;
    476449        \end{cfa}
     450        \vspace*{-10pt}
    477451        that the brands on the generic arguments match the brands of the declared type variables.
    478452        Here, that @foo@ is a type and @bar@ is a dimension.
     
    488462from one party who knows it, to another who is willing to work with any given length.
    489463For scenarios where the concern is a mishandled length,
    490 the interaction is between two parties who both claim to know (something about) it.
    491 Such a scenario occurs in this pure C fragment, wich today's C compilers accept:
    492 \begin{cfa}
    493         int n = @42@;
    494         float x[n];
    495         float (*xp)[@999@] = &x;
    496         (*xp)[@500@];  // in "bound"?
    497 \end{cfa}
    498 
     464the interaction is between two parties who both claim to know something about it.
     465Such a scenario occurs in this pure C fragment, which today's C compilers accept:
     466\begin{cfa}
     467int n = @42@;
     468float x[n];
     469float (*xp)[@999@] = &x;
     470(*xp)[@500@]; $\C{// in "bound"?}$
     471\end{cfa}
    499472Here, the array @x@ has length 42, while a pointer to it (@xp@) claims length 999.
    500473So, while the subscript of @xp@ at position 500 is out of bound of its referent @x@,
     
    505478The \CFA new-array rejects the analogous case:
    506479\begin{cfa}
    507         int n = @42@;
    508         array(float, n) x;
    509         array(float, 999) * xp = x; // static rejection here
    510         (*xp)[@500@]; // runtime check vs len 999
    511 \end{cfa}
    512 
    513 % TODO: kill the vertical whitespace around these lists
    514 % nothing from https://stackoverflow.com/questions/1061112/eliminate-space-before-beginitemize is working
    515 
    516 The way the \CFA array is implemented,
    517 the type analysis of this \CFA case reduces to a case similar to the earlier C version.
     480int n = @42@;
     481array(float, n) x;
     482array(float, 999) * xp = x; $\C{// static rejection here}$
     483(*xp)[@500@]; $\C{// runtime check vs len 999}$
     484\end{cfa}
     485The way the \CFA array is implemented, the type analysis of this case reduces to a case similar to the earlier C version.
    518486The \CFA compiler's compatibility analysis proceeds as:
    519 \begin{itemize}[noitemsep,partopsep=-\parskip,parsep=0pt,leftmargin=4em]
     487\begin{itemize}[parsep=0pt]
    520488\item
    521489        Is @array(float, 999)@ type-compatible with @array(float, n)@?
    522490\item
    523         Is @arrayX(float, char[999])@ type-compatible with @arrayX(float, char[n])@?
    524         \footnote{Here, \lstinline{arrayX} represents the type that results
     491        Is @arrayX(float, char[999])@ type-compatible with @arrayX(float, char[n])@?\footnote{
     492                Here, \lstinline{arrayX} represents the type that results
    525493                from desugaring the \lstinline{array} type
    526494                into a type whose generic parameters are all types.
     
    531499        Is @char[999]@ type-compatible with @char[n]@?
    532500\end{itemize}
    533 
    534 I chose to achieve the necessary rejection of the \CFA case
    535 by adding a rejection of the corresponding C case.
    536 
    537 This decision is not backward compatible.
     501To achieve the necessary \CFA rejections meant rejecting the corresponding C case, which is not backward compatible.
    538502There are two complementary mitigations for this incompatibility.
    539503
     
    542506This situation might arise if @n@ were known to be 999,
    543507rather than 42, as in the introductory examples.
    544 The programmer can add a cast, as in:
    545 \begin{cfa}
    546         xp = ( float (*)[999] ) & x;
    547 \end{cfa}
    548 This addition causes \CFA to accept, beacause now, the programmer has accepted blame.
     508The programmer can add a cast in the \CFA code.
     509\begin{cfa}
     510xp = @(float (*)[999])@ &x;
     511\end{cfa}
     512This addition causes \CFA to accept, because now, the programmer has accepted blame.
    549513This addition is benign in plain C, because the cast is valid, just unnecessary there.
    550514Moreover, the addition can even be seen as appropriate ``eye candy,''
     
    556520Second, the incompatibility only affects types like pointer-to-array,
    557521which are are infrequently used in C.
    558 The more common C idiom for aliasing an array is to use the pointer-to-first-element type,
    559 which does not participate in the \CFA array's length checking.
    560 \footnote{Notably, the desugaring of the \lstinline{array@} type,
    561         avoids letting any \lstinline{-[-]} type decay,
    562         in order to preserve the length information that powers runtime bound checking.}
    563 Therefore, the frequency of needing to upgrade wild C code (as discussed in the first mitigation)
     522The more common C idiom for aliasing an array is to use a pointer-to-first-element type,
     523which does not participate in the \CFA array's length checking.\footnote{
     524        Notably, the desugaring of the \lstinline{array} type avoids letting any \lstinline{-[-]} type decay,
     525        in order to preserve the length information that powers runtime bound-checking.}
     526Therefore, the frequency of needing to upgrade legacy C code (as discussed in the first mitigation)
    564527is anticipated to be low.
    565528
    566529Because the incompatibility represents a low cost to a \CFA onboarding effort
    567530(with a plausible side benefit of linting the original code for a missing annotation),
    568 I elected not to add special measures to retain the compatibility.
     531no special measures were added to retain the compatibility.
    569532It would be possible to flag occurrences of @-[-]@ types that come from @array@ desugaring,
    570533treating those with stricter \CFA rules, while treating others with classic C rules.
     
    573536
    574537Having allowed that both the initial C example's check
    575 \begin{itemize}[noitemsep,partopsep=-\parskip,parsep=0pt,leftmargin=4em]
     538\begin{itemize}
    576539        \item
    577540                Is @float[999]@ type-compatible with @float[n]@?
    578541\end{itemize}
    579 and the second \CFA exmple's induced check
    580 \begin{itemize}[noitemsep,partopsep=-\parskip,parsep=0pt,leftmargin=4em]
     542and the second \CFA example's induced check
     543\begin{itemize}
    581544        \item
    582545                Is @char[999]@ type-compatible with @char[n]@?
     
    587550To implement the new \CFA rules, I took the syntactic recursion a step further, obtaining,
    588551in both cases:
    589 \begin{itemize}[noitemsep,partopsep=-\parskip,parsep=0pt,leftmargin=4em]
     552\begin{itemize}
    590553        \item
    591                 Is @999@ TBD-compatible with @n@?
     554                Is @999@ compatible with @n@?
    592555\end{itemize}
    593 This compatibility question applies to a pair of expressions, where the earlier ones were to types.
     556This compatibility question applies to a pair of expressions, where the earlier implementation were to types.
    594557Such an expression-compatibility question is a new addition to the \CFA compiler.
    595 These questions only arise in the context of dimension expressions on (C) array types.
     558Note, these questions only arise in the context of dimension expressions on (C) array types.
    596559
    597560TODO: ensure these compiler implementation matters are treated under \CFA compiler background:
     
    600563GenPoly.
    601564
    602 The relevant technical component of the \CFA compiler is,
    603 within the type resolver, the type unification procedure.
     565The relevant technical component of the \CFA compiler is the type unification procedure within the type resolver.
    604566I added rules for continuing this unification into expressions that occur within types.
    605567It is still fundamentally doing \emph{type} unification
     
    607569and not participating in binding any variables that stand in for expression fragments
    608570(for there is no such sort of variable in \CFA's analysis.)
    609 
    610571An unfortunate fact about the \CFA compiler's preexisting implementation is that
    611572type unification suffers from two forms of duplication.
     
    613574The first duplication has (many of) the unification rules stated twice.
    614575As a result, my additions for dimension expressions are stated twice.
    615 The extra statement of the rules occurs in the GenPoly module,
     576The extra statement of the rules occurs in the @GenPoly@ module,
    616577where concrete types like @array(int, 5)@\footnote{
    617578        Again, the presentation is simplified
    618         by leaving the \lstinline{array} macro unexpanded}
     579        by leaving the \lstinline{array} macro unexpanded.}
    619580are lowered into corresponding C types @struct __conc_array_1234@ (the suffix being a generated index).
    620 In this case, the struct's definition gives fields that hardcode the argument values of @float@ and @5@.
    621 The next time an @array(-,-)@ concrete instance is encountered,
    622 is the previous @struct __conc_array_1234@ suitable for it?
    623 Yes, for another occurrance of @array(int, 5)@;
     581In this case, the struct's definition contains fields that hardcode the argument values of @float@ and @5@.
     582The next time an @array(-,-)@ concrete instance is encountered, it checks if the previous @struct __conc_array_1234@ is suitable for it.
     583Yes, for another occurrence of @array(int, 5)@;
    624584no, for either @array(rational(int), 5)@ or @array(int, 42)@.
    625585By the last example, this phase must ``reject''
     
    630590In the program
    631591\begin{cfa}
    632         void f( double );
    633         forall( T & ) void f( T & );
    634         void g( int n ) {
    635                 array( float, n + 1 ) x;
    636                 f(x);
    637         }
    638 \end{cfa}
    639 when resolving the function call, the first unification stage
    640 compares the types @T@, of the parameter, with @array( float, n + 1 )@, of the argument.
     592void @f@( double );
     593forall( T & ) void @f@( T & );
     594void g( int n ) {
     595        array( float, n + 1 ) x;
     596        f(x);   // overloaded
     597}
     598\end{cfa}
     599when resolving the function call, @g@, the first unification stage
     600compares the type @T@ of the parameter with @array( float, n + 1 )@, of the argument.
    641601TODO: finish.
    642602
     
    647607        TODO: Deal with directionality, that I'm doing exact-match, no ``at least as long as,'' no subtyping.
    648608        Should it be an earlier scoping principle?  Feels like it should matter in more places than here.}
    649 So, a ``yes'' answer must represent a guarantee that both expressions will evaluate the
    650 same result, while a ``no'' can tolerate ``they might, but we're not sure,'
     609So, a ``yes'' answer must represent a guarantee that both expressions evaluate the
     610same result, while a ``no'' can tolerate ``they might, but we're not sure'',
    651611provided that practical recourses are available
    652 to let programmers express their better knowledge.
    653 The specific rule-set that I offer with the current release is, in fact, extremely conservative.
     612to let programmers express better knowledge.
     613The new rule-set in the current release is, in fact, extremely conservative.
    654614I chose to keep things simple,
    655 and allow real future needs do drive adding additional complexity,
    656 within the framework that I laid out.
     615and allow future needs to drive adding additional complexity, within the new framework.
    657616
    658617For starters, the original motivating example's rejection
     
    662621Rather, the analysis assumes a variable's value can be anything,
    663622and so there can be no guarantee that its value is 999.
    664 So, a variable use and a literal can never match.
     623So, a variable and a literal can never match.
    665624
    666625Two occurrences of the same literal value are obviously a fine match.
    667 For two occurrences of the same varialbe, more information is needed.
     626For two occurrences of the same variable, more information is needed.
    668627For example, this one is fine
    669628\begin{cfa}
    670         void f( const int n ) {
    671                 float x[n];
    672                 float (*xp)[n] = x; // accept
    673         }
     629void f( const int n ) {
     630        float x[n];
     631        float (*xp)[n] = x;  // accept
     632}
    674633\end{cfa}
    675634while this one is not:
    676635\begin{cfa}
    677         void f() {
    678                 int n = 42;
    679                 float x[n];
    680                 n = 999;
    681                 float (*xp)[n] = x; // reject
    682         }
     636void f() {
     637        int n = 42;
     638        float x[n];
     639        n = 999;
     640        float (*xp)[n] = x;  // reject
     641}
    683642\end{cfa}
    684643Furthermore, the fact that the first example sees @n@ as @const@
    685 is not actually a sufficent basis.
     644is not actually sufficient.
    686645In this example, @f@'s length expression's declaration is as @const@ as it can be,
    687646yet its value still changes between the two invocations:
    688 \begin{cfa}
    689         // compile unit 1
    690         void g();
    691         void f( const int & const nr ) {
    692                 float x[nr];
    693                 g();
    694                 float (*xp)[nr] = x; // reject
    695         }
    696         // compile unit 2
    697         static int n = 42;
    698         void g() {
    699                 n = 99;
    700         }
    701         void f( const int & );
    702         int main () {
    703                 f(n);
    704                 return 0;
    705         }
    706 \end{cfa}
    707 The issue in this last case is,
    708 just because you aren't able to change something doesn't mean someone else can't.
    709 
    710 My rule set also respects a feature of the C tradition.
    711 In spite of the several limitations of the C rules
     647\begin{cquote}
     648\setlength{\tabcolsep}{15pt}
     649\begin{tabular}{@{}ll@{}}
     650\begin{cfa}
     651// compile unit 1
     652void g();
     653void f( const int & const nr ) {
     654        float x[nr];
     655        g();    // change n
     656        @float (*xp)[nr] = x;@   // reject
     657}
     658\end{cfa}
     659&
     660\begin{cfa}
     661// compile unit 2
     662static int n = 42;
     663void g() {
     664        n = 99;
     665}
     666
     667f( n );
     668\end{cfa}
     669\end{tabular}
     670\end{cquote}
     671The issue here is that knowledge needed to make a correct decision is hidden by separate compilation.
     672Even within a translation unit, static analysis might not be able to provide all the information.
     673
     674My rule set also respects a traditional C feature: In spite of the several limitations of the C rules
    712675accepting cases that produce different values, there are a few mismatches that C stops.
    713 C is quite precise when working with two static values:
    714 \begin{cfa}
    715         enum { fortytwo = 42 };
    716         float x[fortytwo];
    717         float (*xp1)[42] = &x; // accept
    718         float (*xp2)[999] = &x; // reject
     676C is quite precise when working with two static values.
     677\begin{cfa}
     678enum { fortytwo = 42 };
     679float x[fortytwo];
     680float (*xp1)[42] = &x;    // accept
     681float (*xp2)[999] = &x;  // reject
    719682\end{cfa}
    720683My \CFA rules agree with C's on these cases.
    721684
    722 My rules classify expressions into three groups:
     685In summary, the new rules classify expressions into three groups:
    723686\begin{description}
    724687\item[Statically Evaluable]
    725688        Expressions for which a specific value can be calculated (conservatively)
    726689        at compile-time.
    727         A preexisting \CFA compiler module defines which expressions qualify,
     690        A preexisting \CFA compiler module defines which literals, enumerators, and expressions qualify,
    728691        and evaluates them.
    729         Includes literals and enumeration values.
    730692\item[Dynamic but Stable]
    731         The value of a variable declared as @const@.
    732         Includes a @const@ parameter.
     693        The value of a variable declared as @const@, including a @const@ parameter.
    733694\item[Potentially Unstable]
    734695        The catch-all category.  Notable examples include:
    735         any function-call result (@float x[foo()];@),
    736         the particular function-call result that is a pointer dereference (@void f(const int * n) { float x[*n]; }@), and
     696        any function-call result, @float x[foo()];@,
     697        the particular function-call result that is a pointer dereference, @void f(const int * n)@ @{ float x[*n]; }@, and
    737698        any use of a reference-typed variable.
    738699\end{description}
    739 
    740 My \CFA rules are:
     700Within these groups, my \CFA rules are:
    741701\begin{itemize}
    742702\item
     
    744704        Notably, this rule allows a literal to match with an enumeration value, based on the value.
    745705\item
    746         Accept a Dynamic but Stable pair, if both expressions are written out the same, e.g. refers to same variable declaration.
     706        Accept a Dynamic but Stable pair, if both expressions are written out the same, \eg refers to the same variable declaration.
    747707\item
    748708        Otherwise, reject.
    749         Notably, reject all pairs from the Potentially Unstable group.
    750         Notably, reject all pairs that cross groups.
     709        Notably, reject all pairs from the Potentially Unstable group and all pairs that cross groups.
    751710\end{itemize}
    752 
    753711The traditional C rules are:
    754712\begin{itemize}
     
    759717\end{itemize}
    760718
    761 
    762 \newcommand{\falsealarm}{{\color{orange}\small{*}}}
    763 \newcommand{\allowmisuse}{{\color{red}\textbf{!}}}
    764 \newcommand{\cmark}{\ding{51}} % from pifont
    765 \newcommand{\xmark}{\ding{55}}
    766719\begin{figure}
     720        \newcommand{\falsealarm}{{\color{blue}\small{*}}}
     721        \newcommand{\allowmisuse}{{\color{red}\textbf{!}}}
     722        \newcommand{\cmark}{\ding{51}} % from pifont
     723        \newcommand{\xmark}{\ding{55}}
     724
    767725        \begin{tabular}{@{}l@{\hspace{16pt}}c@{\hspace{8pt}}c@{\hspace{16pt}}c@{\hspace{8pt}}c@{\hspace{16pt}}c}
    768726         & \multicolumn{2}{c}{\underline{Values Equal}}
     
    778736        \end{tabular}
    779737
    780         \vspace{12pt}
    781         \noindent\textbf{Legend:}
    782         \begin{itemize}
     738        \medskip
     739        \noindent\textbf{Legend}
     740        \begin{itemize}[leftmargin=*]
    783741        \item
    784742                Each row gives the treatment of a test harness of the form
    785743                \begin{cfa}
    786                         float x[ expr1 ];
    787                         float (*xp)[ expr2 ] = &x;
     744                float x[ expr1 ];
     745                float (*xp)[ expr2 ] = &x;
    788746                \end{cfa}
    789                 where \lstinline{expr1} and \lstinline{expr2} are metavariables varying according to the row's Case.
     747                \vspace*{-10pt}
     748                where \lstinline{expr1} and \lstinline{expr2} are meta-variables varying according to the row's Case.
    790749                Each row's claim applies to other harnesses too, including,
    791750                \begin{itemize}
    792751                \item
    793                         calling a function with a paramter like \lstinline{x} and an argument of the \lstinline{xp} type,
     752                        calling a function with a parameter like \lstinline{x} and an argument of the \lstinline{xp} type,
    794753                \item
    795754                        assignment in place of initialization,
     
    801760        \item
    802761                Each case's claim is symmetric (swapping \lstinline{expr1} with \lstinline{expr2} has no effect),
    803                 even though most test harnesses are asymetric.
     762                even though most test harnesses are asymmetric.
    804763        \item
    805764                The table treats symbolic identity (Same/Different on rows)
    806                 apart from value eqality (Equal/Unequal on columns).
     765                apart from value equality (Equal/Unequal on columns).
    807766                \begin{itemize}
    808767                \item
     
    819778                while every Accept under Values Unequal is an allowed misuse (\allowmisuse).
    820779        \end{itemize}
    821         \caption{Case comparison for array type compatibility, given pairs of dimension expressions.
    822                 TODO: get Peter's LaTeX help on overall appearance, probably including column spacing/centering and bullet indentation.}
     780
     781        \caption{Case comparison for array type compatibility, given pairs of dimension expressions.}
    823782        \label{f:DimexprRuleCompare}
    824783\end{figure}
     
    826785
    827786Figure~\ref{f:DimexprRuleCompare} gives a case-by-case comparison of the consequences of these rule sets.
    828 It demonstrates that the \CFA false alarms occur in the same cases as C treats unsafely.
    829 It also shows that C-incompatibilities only occur in cases that C treats unsafely.
     787It demonstrates that the \CFA false alarms occur in the same cases as C treats unsafe.
     788It also shows that C-incompatibilities only occur in cases that C treats unsafe.
    830789
    831790
     
    837796whose reuses are rejected by the blunt current-state rules:
    838797\begin{cfa}
    839         void f( int & nr, const int nv ) {
    840                 float x[nr];
    841                 float (*xp)[nr] = & x; // reject: nr varying (no references)
    842                 float y[nv + 1];
    843                 float (*yp)[nv + 1] = & y; // reject: ?+? unpredicable (no functions)
    844         }
     798void f( int & nr, const int nv ) {
     799        float x[nr];
     800        float (*xp)[nr] = &x;  // reject: nr varying (no references)
     801        float y[nv + 1];
     802        float (*yp)[nv + 1] = &y;   // reject: ?+? unpredictable (no functions)
     803}
    845804\end{cfa}
    846805Yet, both dimension expressions are reused safely.
    847 (The @nr@ reference is never written, not volatile
     806The @nr@ reference is never written, not volatile
    848807and control does not leave the function between the uses.
    849 The name @?+?@ resolves to a function that is quite predictable.)
    850 The programmer here can add the constant declarations:
    851 \begin{cfa}
    852         void f( int & nr, const int nv ) {
    853                 @const int nx@ = nr;
    854                 float x[nx];
    855                 float (*xp)[nx] = & x; // acept
    856                 @const int ny@ = nv + 1;
    857                 float y[ny];
    858                 float (*yp)[ny] = & y; // accept
    859         }
     808The name @?+?@ resolves to a function that is quite predictable.
     809Here, the programmer can add the constant declarations (cast does not work):
     810\begin{cfa}
     811void f( int & nr, const int nv ) {
     812        @const int nx@ = nr;
     813        float x[nx];
     814        float (*xp)[nx] = & x;   // accept
     815        @const int ny@ = nv + 1;
     816        float y[ny];
     817        float (*yp)[ny] = & y;  // accept
     818}
    860819\end{cfa}
    861820The result is the originally intended semantics,
     
    863822
    864823The snapshotting trick is also used by the translation, though to achieve a different outcome.
    865 Rather obviously, every array must be subscriptable, even a bizzarre one:
    866 \begin{cfa}
    867         array( float, rand(10) ) x;
    868         x[0];  // 10% chance of bound-check failure
     824Rather obviously, every array must be subscriptable, even a bizarre one:
     825\begin{cfa}
     826array( float, rand(10) ) x;
     827x[0];  // 10% chance of bound-check failure
    869828\end{cfa}
    870829Less obvious is that the mechanism of subscripting is a function call,
     
    874833Adjusting the example to make the function's use of length more explicit:
    875834\begin{cfa}
    876         forall ( T * )
    877         void f( T * x ) { sout | sizeof(*x); }
    878         float x[ rand(10) ];
    879         f( x );
     835forall ( T * )
     836void f( T * x ) { sout | sizeof(*x); }
     837float x[ rand(10) ];
     838f( x );
    880839\end{cfa}
    881840Considering that the partly translated function declaration is, loosely,
    882841\begin{cfa}
    883         void f( size_t __sizeof_T, void * x ) { sout | __sizeof_T; }
    884 \end{cfa}
    885 the translated call must not go like:
    886 \begin{cfa}
    887         float x[ rand(10) ];
    888         f( rand(10), &x );
    889 \end{cfa}
    890 Rather, its actual translation is like:
    891 \begin{cfa}
    892         size_t __dim_x = rand(10);
    893         float x[ __dim_x ];
    894         f( __dim_x, &x );
    895 \end{cfa}
    896 The occurrence of this dimension hoisting during translation was present in the preexisting \CFA compiler.
    897 But its cases were buggy, particularly with determining, ``Can hoisting be skipped here?''
    898 For skipping this hoisting is clearly desirable in some cases,
    899 not the least of which is when the programmer has already done so manually.
    900 My work includes getting these cases right, harmonized with the accept/reject criteria, and tested.
    901 
    902 
     842void f( size_t __sizeof_T, void * x ) { sout | __sizeof_T; }
     843\end{cfa}
     844the translation must call the dimension argument twice:
     845\begin{cfa}
     846float x[ rand(10) ];
     847f( rand(10), &x );
     848\end{cfa}
     849Rather, the translation is:
     850\begin{cfa}
     851size_t __dim_x = rand(10);
     852float x[ __dim_x ];
     853f( __dim_x, &x );
     854\end{cfa}
     855The occurrence of this dimension hoisting during translation was in the preexisting \CFA compiler.
     856But its cases were buggy, particularly with determining, ``Can hoisting the expression be skipped here?'', for skipping this hoisting is clearly desirable in some cases.
     857For example, when the programmer has already done so manually. \PAB{I don't know what this means.}
     858In the new implementation, these cases are correct, harmonized with the accept/reject criteria.
    903859
    904860TODO: Discuss the interaction of this dimension hoisting with the challenge of extra unification for cost calculation
    905861
    906862
    907 \section{Multidimensional Arrays}
    908 \label{toc:mdimpl}
    909 
    910 % TODO: introduce multidimensional array feature and approaches
    911 
    912 When working with arrays, \eg linear algebra, array dimensions are referred to as ``rows'' and ``columns'' for a matrix, adding ``planes'' for a cube.
    913 (There is little terminology for higher dimensional arrays.)
    914 For 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.}
    915 can be treated as a grid of characters, where the rows are the text and the columns are the embedded keyword(s).
    916 Within a poem, there is the concept of a \newterm{slice}, \eg a row is a slice for the poem text, a column is a slice for a keyword.
    917 In general, the dimensioning and subscripting for multidimensional arrays has two syntactic forms: @m[r,c]@ or @m[r][c]@.
    918 
    919 Commonly, an array, matrix, or cube, is visualized (especially in mathematics) as a contiguous row, rectangle, or block.
    920 This conceptualization is reenforced by subscript ordering, \eg $m_{r,c}$ for a matrix and $c_{p,r,c}$ for a cube.
    921 Few programming languages differ from the mathematical subscript ordering.
    922 However, computer memory is flat, and hence, array forms are structured in memory as appropriate for the runtime system.
    923 The closest representation to the conceptual visualization is for an array object to be contiguous, and the language structures this memory using pointer arithmetic to access the values using various subscripts.
    924 This approach still has degrees of layout freedom, such as row or column major order, \ie juxtaposed rows or columns in memory, even when the subscript order remains fixed.
    925 For example, programming languages like MATLAB, Fortran, Julia and R store matrices in column-major order since they are commonly used for processing column-vectors in tabular data sets but retain row-major subscripting.
    926 In general, storage layout is hidden by subscripting, and only appears when passing arrays among different programming languages or accessing specific hardware.
    927 
    928 \VRef[Figure]{f:FixedVariable} shows two C90 approaches for manipulating a contiguous matrix.
    929 Note, C90 does not support VLAs.
    930 The fixed-dimension approach (left) uses the type system;
    931 however, it requires all dimensions except the first to be specified at compile time, \eg @m[][6]@, allowing all subscripting stride calculations to be generated with constants.
    932 Hence, every matrix passed to @fp1@ must have exactly 6 columns but the row size can vary.
    933 The variable-dimension approach (right) ignores (violates) the type system, \ie argument and parameters types do not match, and subscripting is performed manually using pointer arithmetic in the macro @sub@.
    934 
    935 \begin{figure}
    936 \begin{tabular}{@{}l@{\hspace{40pt}}l@{}}
    937 \multicolumn{1}{c}{\textbf{Fixed Dimension}} & \multicolumn{1}{c}{\textbf{Variable Dimension}} \\
    938 \begin{cfa}
    939 
    940 void fp1( int rows, int m[][@6@] ) {
    941         ...  printf( "%d ", @m[r][c]@ );  ...
    942 }
    943 int fm1[4][@6@], fm2[6][@6@]; // no VLA
    944 // initialize matrixes
    945 fp1( 4, fm1 ); // implicit 6 columns
    946 fp1( 6, fm2 );
    947 \end{cfa}
    948 &
    949 \begin{cfa}
    950 #define sub( m, r, c ) *(m + r * sizeof( m[0] ) + c)
    951 void fp2( int rows, int cols, int *m ) {
    952         ...  printf( "%d ", @sub( m, r, c )@ );  ...
    953 }
    954 int vm1[@4@][@4@], vm2[@6@][@8@]; // no VLA
    955 // initialize matrixes
    956 fp2( 4, 4, vm1 );
    957 fp2( 6, 8, vm2 );
    958 \end{cfa}
    959 \end{tabular}
    960 \caption{C90 Fixed \vs Variable Contiguous Matrix Styles}
    961 \label{f:FixedVariable}
    962 \end{figure}
    963 
    964 Many languages allow multidimensional arrays-of-arrays, \eg in Pascal or \CC.
    965 \begin{cquote}
    966 \begin{tabular}{@{}ll@{}}
    967 \begin{pascal}
    968 var m : array[0..4, 0..4] of Integer;  (* matrix *)
    969 type AT = array[0..4] of Integer;  (* array type *)
    970 type MT = array[0..4] of AT;  (* array of array type *)
    971 var aa : MT;  (* array of array variable *)
    972 m@[1][2]@ := 1;   aa@[1][2]@ := 1 (* same subscripting *)
    973 \end{pascal}
    974 &
    975 \begin{c++}
    976 int m[5][5];
    977 
    978 typedef vector< vector<int> > MT;
    979 MT vm( 5, vector<int>( 5 ) );
    980 m@[1][2]@ = 1;  aa@[1][2]@ = 1;
    981 \end{c++}
    982 \end{tabular}
    983 \end{cquote}
    984 The language decides if the matrix and array-of-array are laid out the same or differently.
    985 For example, an array-of-array may be an array of row pointers to arrays of columns, so the rows may not be contiguous in memory nor even the same length (triangular matrix).
    986 Regardless, there is usually a uniform subscripting syntax masking the memory layout, even though a language could differentiated between the two forms using subscript syntax, \eg @m[1,2]@ \vs @aa[1][2]@.
    987 Nevertheless, controlling memory layout can make a difference in what operations are allowed and in performance (caching/NUMA effects).
    988 
    989 C also provides non-contiguous arrays-of-arrays.
    990 \begin{cfa}
    991 int m[5][5];                                                    $\C{// contiguous}$
    992 int * aa[5];                                                    $\C{// non-contiguous}$
    993 \end{cfa}
    994 both with different memory layout using the same subscripting, and both with different degrees of issues.
    995 The focus of this work is on the contiguous multidimensional arrays in C.
    996 The reason is that programmers are often forced to use the more complex array-of-array form when a contiguous array would be simpler, faster, and safer.
    997 Nevertheless, the C array-of-array form is still important for special circumstances.
    998 
    999 \VRef[Figure]{f:ContiguousNon-contiguous} shows the extensions made in C99 for manipulating contiguous \vs non-contiguous arrays.\footnote{C90 also supported non-contiguous arrays.}
    1000 First, VLAs are supported.
    1001 Second, for contiguous arrays, 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@.
    1002 If the declaration of @fc@ is changed to:
    1003 \begin{cfa}
    1004 void fc( int rows, int cols, int m[@rows@][@cols@] ) ...
    1005 \end{cfa}
    1006 it is possible for C to perform bound checking across all subscripting, but it does not.
    1007 While this contiguous-array capability is a step forward, it is still the programmer's responsibility to manually manage the number of dimensions and their sizes, both at the function definition and call sites.
    1008 That is, the array does not automatically carry its structure and sizes for use in computing subscripts.
    1009 While the non-contiguous style in @faa@ looks very similar to @fc@, the compiler only understands the unknown-sized array of row pointers, and it relies on the programmer to traverse the columns in a row correctly with a correctly bounded loop index.
    1010 Specifically, there is no requirement that the rows are the same length, like a poem with different length lines.
    1011 
    1012 \begin{figure}
    1013 \begin{tabular}{@{}ll@{}}
    1014 \multicolumn{1}{c}{\textbf{Contiguous}} & \multicolumn{1}{c}{\textbf{ Non-contiguous}} \\
    1015 \begin{cfa}
    1016 void fc( int rows, @int cols@, int m[ /* rows */ ][@cols@] ) {
    1017         ...  printf( "%d ", @m[r][c]@ );  ...
    1018 }
    1019 int m@[5][5]@;
    1020 for ( int r = 0; r < 5; r += 1 ) {
    1021 
    1022         for ( int c = 0; c < 5; c += 1 )
    1023                 m[r][c] = r + c;
    1024 }
    1025 fc( 5, 5, m );
    1026 \end{cfa}
    1027 &
    1028 \begin{cfa}
    1029 void faa( int rows, int cols, int * m[ @/* cols */@ ] ) {
    1030         ...  printf( "%d ", @m[r][c]@ );  ...
    1031 }
    1032 int @* aa[5]@;  // row pointers
    1033 for ( int r = 0; r < 5; r += 1 ) {
    1034         @aa[r] = malloc( 5 * sizeof(int) );@ // create rows
    1035         for ( int c = 0; c < 5; c += 1 )
    1036                 aa[r][c] = r + c;
    1037 }
    1038 faa( 5, 5, aa );
    1039 \end{cfa}
    1040 \end{tabular}
    1041 \caption{C99 Contiguous \vs Non-contiguous Matrix Styles}
    1042 \label{f:ContiguousNon-contiguous}
    1043 \end{figure}
    1044 
    1045 
    1046 \subsection{Multidimensional array implementation}
     863\section{Multidimensional array implementation}
    1047864\label{s:ArrayMdImpl}
    1048865
     
    12211038        S & | sized(S),                 $\C{// masquerading-as}$
    12221039        Timmed &,                               $\C{// immediate element, often another array}$
    1223         Tbase &                                 $\C{// base element, e.g. float, never array}$
     1040        Tbase &                                 $\C{// base element, \eg float, never array}$
    12241041) { // distribute forall to each element
    12251042        struct arpk {
     
    12741091
    12751092
    1276 
    1277 
     1093\section{Array lifecycle}
     1094
     1095An array is an aggregate, like a structure;
     1096both are containers wrapping subordinate objects.
     1097Any arbitrary object type, like @string@, can be an array element or structure member.
     1098A consequence is that the lifetime of the container must match with its subordinate objects: all elements and members must be initialized/uninitialized implicitly as part of the container's allocation/deallocation.
     1099Modern programming languages implicitly perform these operations via a type's constructor and destructor.
     1100Therefore, \CFA must assure that an array's subordinate objects' lifetime operations are called.
     1101
     1102Preexisting \CFA mechanisms achieve this requirement, but with poor performance.
     1103Furthermore, advanced array users need an exception to the basic mechanism, which does not occur with other aggregates.
     1104Hence, arrays introduce subleties in supporting an element's lifecycle.
     1105
     1106The preexisting \CFA support for contained-element lifecycle is based on recursive occurrences of the object-type (@otype@) pseudo-trait.
     1107A type is an @otype@, if it provides a default (parameterless) constructor, copy constructor, assignment operator, and destructor (like \CC).
     1108When declaring a structure with @otype@ members, the compiler implicitly generates implementations of the four @otype@ functions for the outer structure.
     1109Then the generated default constructor for the outer structure calls the default constructor for each member, and the other @otype@ functions work similarly.
     1110For a member that is a C array, these calls occur in a loop for each array element, which even works for VLAs.
     1111This logic works the same, whether the member is a concrete type (that happens to be an @otype@) or if the member is a polymorphic type asserted to be an @otype@ (which is implicit in the syntax, @forall(T)@).
     1112The \CFA array has the simplified form (similar to one seen before):
     1113\begin{cfa}
     1114forall( T * )   // non-otype element, no lifecycle functions
     1115// forall( T )  // otype element, lifecycle functions asserted
     1116struct array5 {
     1117        T __items[ 5 ];
     1118};
     1119\end{cfa}
     1120Being a structure with a C-array member, using the otype-form declaration for @T@ causes @array5(float)@ to implement @otype@ too.
     1121
     1122But this @otype@-recursion pattern has a performance issue.
     1123For example, in a cube of @float@:
     1124\begin{cfa}
     1125array5( array5( array5( float ) ) )
     1126\end{cfa}
     1127the first few steps of the compiler's work to find the lifecycle functions, under the @otype@-recursion pattern, are shown in \VRef[Figure]{f:OtypeRecursionBlowup}.
     1128All the work needed for the full @float@-cube would have 256 leaves.
     1129
     1130%array5(T) offers
     1131%1 parameterless ctor, which asks for T to have
     1132%       1 parameterless ctor
     1133%       2 copy ctor
     1134%       3 asgt
     1135%       4 dtor
     1136%2 copy ctor, which asks for T to have
     1137%       1 parameterless ctor
     1138%       2 copy ctor
     1139%       3 asgt
     1140%       4 dtor
     1141%3 asgt, which asks for T to have
     1142%       1 parameterless ctor
     1143%       2 copy ctor
     1144%       3 asgt
     1145%       4 dtor
     1146%4 dtor, which asks for T to have
     1147%       1 parameterless ctor
     1148%       2 copy ctor
     1149%       3 asgt
     1150%       4 dtor
     1151
     1152\begin{figure}
     1153\centering
     1154\setlength{\tabcolsep}{15pt}
     1155\begin{tabular}{@{}lll@{}}
     1156\begin{cfa}[deletekeywords={default}]
     1157float offers
     11581 default ctor
     11592 copy ctor
     11603 asgt
     11614 dtor
     1162
     1163
     1164
     1165
     1166
     1167
     1168
     1169
     1170
     1171
     1172
     1173
     1174
     1175
     1176
     1177
     1178
     1179
     1180
     1181
     1182
     1183
     1184
     1185
     1186\end{cfa}
     1187&
     1188\begin{cfa}[deletekeywords={default}]
     1189array5(float) has
     11901 default ctor, using float's
     1191        1 default ctor
     1192        2 copy ctor
     1193        3 asgt
     1194        4 dtor
     11952 copy ctor, using float's
     1196        1 default ctor
     1197        2 copy ctor
     1198        3 asgt
     1199        4 dtor
     12003 asgt, using float's
     1201        1 default ctor
     1202        2 copy ctor
     1203        3 asgt
     1204        4 dtor
     12054 dtor, using float's
     1206        1 default ctor
     1207        2 copy ctor
     1208        3 asgt
     1209        4 dtor
     1210
     1211
     1212
     1213
     1214
     1215
     1216
     1217
     1218\end{cfa}
     1219&
     1220\begin{cfa}[deletekeywords={default}]
     1221array5(array5(float)) has
     12221 default ctor, using array5(float)'s
     1223        1 default ctor, using float's
     1224                1 default ctor
     1225                2 copy ctor
     1226                3 asgt
     1227                4 dtor
     1228        2 copy ctor, using float's
     1229                1 default ctor
     1230                2 copy ctor
     1231                3 asgt
     1232                4 dtor
     1233        3 asgt, using float's
     1234                1 default ctor
     1235                2 copy ctor
     1236                3 asgt
     1237                4 dtor
     1238        4 dtor, using float's
     1239                1 default ctor
     1240                2 copy ctor
     1241                3 asgt
     1242                4 dtor
     12432 copy ctor, using array5(float)'s
     1244        ... 4 children, 16 leaves
     12453 asgt, using array5(float)'s
     1246        ... 4 children, 16 leaves
     12474 dtor, using array5(float)'s
     1248        ... 4 children, 16 leaves
     1249(64 leaves)
     1250\end{cfa}
     1251\end{tabular}
     1252\caption{Exponential thunk generation under the otype-recursion pattern.
     1253        Each time that one type's function (\eg ctor) uses another type's function, the \CFA compiler generates a thunk, to capture the used function's dependencies, presented according to the using function's need.
     1254        So, each non-leaf line represents a generated thunk and every line represents a search request for the resolver to find a satisfying function.}
     1255\label{f:OtypeRecursionBlowup}
     1256\end{figure}
     1257
     1258So the @otype@-recursion pattern seeks a quantity of helper functions, and generates a quantity of thunks, that are exponential in the number of dimensions.
     1259Anecdotal experience with this solution found the resulting compile times annoyingly slow at three dimensions, and unusable at four.
     1260
     1261The issue is that the otype-recursion pattern uses more assertions than needed.
     1262Consider how @array5(float)@'s default constructor is getting all four lifecycle assertions about the element type, @float@.
     1263It only needs @float@'s default constructor;
     1264the full set of operations is never used.
     1265Current work by the \CFA team aims to improve this situation.
     1266Therefore, a workaround is needed for now.
     1267
     1268The workaround is to provide a default constructor, copy constructor and destructor, defined with lean, bespoke assertions:
     1269\begin{cquote}
     1270\begin{tabular}{@{}l@{\hspace{0.5in}}l@{}}
     1271\begin{cfa}
     1272// autogenerated for otype-recursion:
     1273forall( T )
     1274void ?{}( array5(T) & this ) {
     1275        for (i; 5) { ( this[i] ){}; }
     1276}
     1277forall( T )
     1278void ?{}( array5(T) & this, array5(T) & src ) {
     1279        for (i; 5) { ( this[i] ){ src[i] }; }
     1280}
     1281forall( T )
     1282void ^?{}( array5(T) & this ) {
     1283        for (i; 5) { ^( this[i] ){}; }
     1284}
     1285\end{cfa}
     1286&
     1287\begin{cfa}
     1288// lean, bespoke:
     1289forall( T* | { void @?{}( T & )@; } )
     1290void ?{}( array5(T) & this ) {
     1291        for (i; 5) { ( this[i] ){}; }
     1292}
     1293forall( T* | { void @?{}( T &, T )@; } )
     1294void ?{}( array5(T) & this, array5(T) & src ) {
     1295        for (i; 5) { ( this[i] ){ src[i] }; }
     1296}
     1297forall( T* | { void @?{}( T & )@; } )
     1298void ^?{}( array5(T) & this ) {
     1299        for (i; 5) { ^( this[i] ){}; }
     1300}
     1301\end{cfa}
     1302\end{tabular}
     1303\end{cquote}
     1304Moreover, the assignment operator is skipped, to avoid hitting a lingering growth case.
     1305Skipping assignment is tolerable because array assignment is not a common operation.
     1306With this solution, the critical lifecycle functions are available, with no growth in thunk creation.
     1307
     1308Finally, the intuition that a programmer using an array always wants the elements' default constructor called \emph{automatically} is simplistic.
     1309Arrays exist to store different values at each position.
     1310So, array initialization needs to let the programmer provide different constructor arguments to each element.
     1311\begin{cfa}
     1312thread worker { int id; };
     1313void ?{}( worker & ) = void; // remove default constructor
     1314void ?{}( worker &, int id );
     1315array( worker, 5 ) ws = @{}@; // rejected; but desire is for no initialization yet
     1316for (i; 5) (ws[i]){ @i@ }; // explicitly initialize each thread, giving id
     1317\end{cfa}
     1318Note the use of the \CFA explicit constructor call, analogous to \CC's placement-@new@.
     1319This call is where initialization is desired, and not at the declaration of @ws@.
     1320The attempt to initialize from nothing (equivalent to dropping @= {}@ altogether) is invalid because the @worker@ type removes the default constructor.
     1321The @worker@ type is designed this way to work with the threading system.
     1322A thread type forks a thread at the end of each constructor and joins with it at the start of each destructor.
     1323But a @worker@ cannot begin its forked-thead work without knowing its @id@.
     1324Therefore, there is a conflict between the implicit actions of the builtin @thread@ type and a user's desire to defer these actions.
     1325
     1326Another \CFA feature may, at first, seem viable for initializing the array @ws@, though on closer inspection, it is not.
     1327C initialization, \lstinline|array(worker, 5) ws @= {};|, ignores all \CFA lifecycle management and uses C empty initialization.
     1328This option does achieve the desired semantics on the construction side.
     1329But on destruction side, the desired semantics is for implicit destructor calls to continue, to keep the join operation tied to lexical scope.
     1330C initialization disables \emph{all} implicit lifecycle management, but the goal is to disable only the implicit construction.
     1331
     1332To fix this problem, I enhanced the \CFA standard library to provide the missing semantics, available in either form:
     1333\begin{cfa}
     1334array( @uninit@(worker), 5 ) ws1;
     1335array( worker, 5) ws2 = { @delay_init@ };
     1336\end{cfa}
     1337Both cause the @ws@-construction-time implicit call chain to stop before reaching a @worker@ constructor, while leaving the implicit destruction calls intact.
     1338Two forms are available, to parallel the development of this feature in \uCpp.
     1339Originally \uCpp offered only the @ws1@ form, using the class-template @uNoCtor@ equivalent to \CFA's @uninit@.
     1340More recently, \uCpp was extended with the declaration macro, @uArray@, with usage similar to the @ws2@ case.
     1341Based on experience piloting @uArray@ as a replacement of @uNoCtor@, it might be possible to remove the first option.
     1342
     1343% note to Mike, I have more fragments on some details available in push24\fragments\uNoCtor.txt
    12781344
    12791345\section{Comparison with other arrays}
  • doc/theses/mike_brooks_MMath/background.tex

    rb006c51e r10a9479d  
    178178\lstinput{34-34}{bkgd-carray-arrty.c}
    179179The inspection begins by using @sizeof@ to provide program semantics for the intuition of an expression's type.
    180 An architecture with 64-bit pointer size is used, to keep irrelevant details fixed.
     180An architecture with 64-bit pointer size is used, to remove irrelevant details.
    181181\lstinput{35-36}{bkgd-carray-arrty.c}
    182182Now consider the @sizeof@ expressions derived from @ar@, modified by adding pointer-to and first-element (and including unnecessary parentheses to avoid any confusion about precedence).
     
    215215
    216216My observation is recognizing:
    217 \begin{itemize}[leftmargin=*,topsep=0pt,itemsep=0pt]
     217\begin{itemize}[leftmargin=*,itemsep=0pt]
    218218        \item There is value in using a type that knows its size.
    219219        \item The type pointer to the (first) element does not.
     
    302302
    303303In summary, when a function is written with an array-typed parameter,
    304 \begin{itemize}[leftmargin=*,topsep=0pt]
     304\begin{itemize}[leftmargin=*]
    305305        \item an appearance of passing an array by value is always an incorrect understanding,
    306306        \item a dimension value, if any is present, is ignored,
     
    532532\subsection{Array Parameter Declaration}
    533533
    534 Passing an array along with a function call is obviously useful.
    535 Let us say that a parameter is an array parameter when the called 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 @T@s,'' and calls out the minority cases where the C type system is using or verifying such claims.
    537 
    538 A C function's parameter declarations look different, from the caller's and callee's perspectives.
     534Passing an array as an argument to a function is necessary.
     535Assume a parameter is an array when the function intends to subscript it.
     536This 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
     538A C parameter declarations look different, from the caller's and callee's perspectives.
    539539Both perspectives consist of the text read by a programmer and the semantics enforced by the type system.
    540 The caller's perspecitve is available from a mere function declaration (which allow definition-before-use and separate compilation), but can also be read from (the non-body part of) a function definition.
     540The 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.
    541541The callee's perspective is what is available inside the function.
    542542\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's; callee's perspective of bar's */$
    546                 ...
    547         }
    548         $/* caller's persepectives of foo's and bar's */$
    549 \end{cfa}
    550 The caller's perspective is more limited.
    551 The example shows, so far, that parameter names (by virtue of being optional) are really comments in the caller's perspective, while they are semantically significant in the callee's perspective.
     543int foo( int, float, char );                            $\C{// declaration, names optional}$
     544int bar( int i, float f, char c ) {             $\C{// definition, names mandatory}$
     545        // caller's perspective of foo; callee's perspective of bar
     546}
     547// caller's perspectives of foo's and bar's
     548\end{cfa}
     549In caller's perspective, the parameter names (by virtue of being optional) are really comments;
     550in the callee's perspective, parameter names are semantically significant.
    552551Array parameters introduce a further, subtle, semantic difference and considerable freedom to comment.
    553552
    554 At the semantic level, there is no such thing as an array parameter, except for one case (@T[static 5]@) discussed shortly.
     553At the semantic level, there is no such thing as an array parameter, except for one case (@T [static 5]@) discussed shortly.
    555554Rather, there are only pointer parameters.
    556 This fact probably shares considerable responsibility for the common sense of ``an array is just a pointer,'' wich has been refuted in non-parameter contexts.
     555This fact probably shares considerable responsibility for the common sense of ``an array is just a pointer,'' which has been refuted in non-parameter contexts.
    557556This fact holds in both the caller's and callee's perspectives.
    558 However, a parameter's type can include ``array of.''
    559 For example, the type ``pointer to array of 5 ints'' (@T(*)[5]@) is a pointer type, a fully meaningful parameter type (in the sense that this description does not contain any information that the type system ignores), and a type that appears the same in the caller's \vs callee's perspectives.
    560 The outermost type constructor (syntactically first dimension) is really the one that determines the flavour of parameter.
     557However, a parameter's type can include ``array of.'', \eg the type ``pointer to array of 5 ints'' (@T (*)[5]@) is a pointer type.
     558This 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.
     559In fact, the outermost type constructor (syntactically first dimension) is really the one that determines the flavour of parameter.
     560
     561Yet, C allows array syntax for the outermost type constructor, from which comes the freedom to comment.
     562An 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}.
     563The 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.
    561564
    562565\begin{figure}
     
    596599\end{tabular}
    597600\end{cquote}
    598 \caption{Multiple ways to declare an arrray parameter.  Across a valid row, every declaration is equivalent.  Each column gives a declaration style.  Really, the style can be read from the first row only.  The second row shows how the style extends to multiple dimensions, with the rows thereafter providing context for the choice of which second-row \lstinline{[]}receives the column-style variation.}
     601\caption{Multiple ways to declare an array parameter.
     602Across a valid row, every declaration is equivalent.
     603Each column gives a declaration style, where the style for that column is read from the first row.
     604The second row begins the style for multiple dimensions, with the rows thereafter providing context for the choice of which second-row \lstinline{[]} receives the column-style variation.}
    599605\label{f:ArParmEquivDecl}
    600606\end{figure}
    601607
    602 Yet, C allows array syntax for the outermost type constructor, from which comes the freedom to comment.
    603 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}.  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.
    604 
    605 In the lefmost style, the typechecker ignores the actual value in most practical cases.
    606 This value is allowed to be a dynamic expression, so it is \emph{possible} to use the leftmost style in many practical cases.
     608In the leftmost style, the typechecker ignores the actual value in most practical cases.
     609This value is allowed to be a dynamic expression, and then it has practical cases.
     610\begin{cfa}
     611void foo( int @n@ ) {
     612        float _42( float @a[n]@ ) {    // nested function
     613                a[0] = 42;
     614        }
     615        float b[n];
     616        _42( b );
     617}
     618\end{cfa}
     619
    607620
    608621% To help contextualize the matrix part of this example, the syntaxes @float [5][]@, @float [][]@ and @float (*)[]@ are all rejected, for reasons discussed shortly.
    609622% 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 **@.
    610623
    611 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 syntactically integrated comments), 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 this one'').
    612 
    613 Note that this equivalence of pointer and array declarations is special to paramters.
     624It 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).
     625
     626Note that this equivalence of pointer and array declarations is special to parameters.
    614627It does not apply to local variables, where true array declarations are possible.
    615628\begin{cfa}
     
    626639float sum( float v[] );
    627640float arg = 3.14;
    628 sum( &arg );                                                            $\C{// accepted, v := \&arg}$
     641sum( &arg );                                                            $\C{// accepted, v = \&arg}$
    629642\end{cfa}
    630643
     
    672685Here, the distance between the first and second elements of each array depends on the inner dimension size.
    673686
    674 The last observation is a fact of the callee's perspective.
    675 There is little type-system checking, in the caller's perspective, that what is being passed, matches.
    676 \begin{cfa}
    677 void f( float [][10] );
    678 int n = 100;
    679 float a[100], b[n];
    680 f(&a); // reject
    681 f(&b); // accept
    682 \end{cfa}
    683 This size is therefore, a callee's assumption.
    684 
    685 Finally, to handle higher-dimensional VLAs, C repurposed the @*@ \emph{within} the dimension in a declaration to mean that the callee will have make an assumption about the size here, but no (unchecked, possibly wrong) information about this assumption is included for the caller-programmer's benefit/overconfidence.
     687This significance of an inner dimension's length is a fact of the callee's perspective.
     688In the caller's perspective, the type sytem is quite lax.
     689Here, there is (some, but) little checking that what is being passed, matches.
     690% void f( float [][10] );
     691% int n = 100;
     692% float a[100], b[n];
     693% f(&a); // reject
     694% f(&b); // accept
     695\begin{cfa}
     696void foo() {
     697        void f( float [][10] );
     698        int n = 100;
     699        float a[100], b[3][12], c[n], d[n][n];
     700        f( a );
     701        f( b );    $\C{// reject: inner dimension 12 for 10}$
     702        f( c );
     703        f( @d@ );  $\C{// accept with inner dimension n for 10}$
     704        f( &a );   $\C{// reject: inner dimension 100 for 10}$
     705        f( &b );
     706        f( @&c@ ); $\C{// accept with inner dimension n for 10}$
     707        f( &d );
     708}
     709\end{cfa}
     710The 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.
     711The cases @f(b)@ and @f(&a)@ show where some length checking occurs.
     712But this checking misses the cases @f(d)@ and @f(&c)@, allowing the calls with mismatched lengths, actually 100 for 10.
     713The C checking rule avoids false alarms, at the expense of safety, by allowing any combinations that involve dynamic values.
     714Ultimately, 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.
     715
     716Finally, 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.
    686717\begin{cquote}
    687718@[@ \textit{type-qualifier-list$_{opt}$} @* ]@
     
    11621193with all the variance being due to the (inevitable) cache status of the nodes being managed.
    11631194
     1195
    11641196\section{String}
     1197\label{s:String}
    11651198
    11661199A string is a sequence of symbols, where the form of a symbol can vary significantly: 7/8-bit characters (ASCII/Latin-1), or 2/4/8-byte (UNICODE) characters/symbols or variable length (UTF-8/16/32) characters.
  • doc/theses/mike_brooks_MMath/programs/hello-accordion.cfa

    rb006c51e r10a9479d  
    3030forall( [C], [S] )
    3131int getPref( @School( C, S ) & school@, int is, int pref ) {
    32     for ( ic; C ) {
    33         int curPref = @school.preferences@[ic][is];   $\C{// offset calculation implicit}$
     32        for ( ic; C ) {
     33                int curPref = @school.preferences@[ic][is];   $\C{// offset calculation implicit}$
    3434                if ( curPref == pref ) return ic;
    3535        }
    36     assert( false );
     36        assert( false );
    3737}
    3838
     
    5959
    6060        {       string sv;
    61         int iv;
    62         // headers' row
    63         sin | "\nc\\s";
    64         for ( is ; ns ) {
    65             // column label
    66             sin | sv;
    67             school.student_ids[is] = sv;
    68         }
    69         // body rows
    70         for ( ic ; nc ) {
    71             // row label
    72             sin | sv;
    73             school.course_codes[ic] = sv;
    74             for ( is ; ns ) {
    75                 // matrix item
    76                 sin | iv;
    77                 school.preferences[ic][is] = iv;
    78             }
    79         }
    80     }
     61                int iv;
     62                // headers' row
     63                sin | "\nc\\s";
     64                for ( is ; ns ) {
     65                        // column label
     66                        sin | sv;
     67                        school.student_ids[is] = sv;
     68                }
     69                // body rows
     70                for ( ic ; nc ) {
     71                        // row label
     72                        sin | sv;
     73                        school.course_codes[ic] = sv;
     74                        for ( is ; ns ) {
     75                                // matrix item
     76                                sin | iv;
     77                                school.preferences[ic][is] = iv;
     78                        }
     79                }
     80        }
    8181
    8282
     
    9191                sout | school.student_ids[is] | ": " | nonl;
    9292                for ( pref; 1 ~= nc ) {
    93             int ic = getPref(school, is, pref);
    94             sout | school.course_codes[ ic ] | nonl;
     93                        int ic = getPref(school, is, pref);
     94                        sout | school.course_codes[ ic ] | nonl;
    9595                }
    9696                sout | nl;
  • doc/theses/mike_brooks_MMath/programs/hello-array.cfa

    rb006c51e r10a9479d  
    114114        f( y, y );              $\C{// ok}$
    115115        if ( M == N )
    116                 f( x, @(array( float, M ) &)@y ); $\C{// ok}$
     116                f( x, @(array( float, M ) &)@y ); $\C{// ok}\CRT$
    117117}
    118118
  • doc/theses/mike_brooks_MMath/programs/sharing-demo.cfa

    rb006c51e r10a9479d  
    55#define str(s) #s
    66
     7ofstream outfile;
     8
    79void demo1() {
    810        sout | sepOff;
    9         sout | "Consider two strings @s1@ and @s1a@ that are in an aliasing relationship, and a third, @s2@, made by a simple copy from @s1@.";
    10         sout | "\\par\\noindent";
    11         sout | "\\begin{tabular}{llll}";
    12         sout | "\t\t\t\t& @s1@\t& @s1a@\t& @s2@\t\\\\";
     11//      sout | "Consider two strings @s1@ and @s1a@ that are in an aliasing relationship, and a third, @s2@, made by a simple copy from @s1@.";
    1312
    1413        #define S1 string s1  = "abc"
     
    2120        assert( s1a == "abc" );
    2221        assert( s2 == "abc" );
    23         sout | xstr(S1) | "\t\\\\";
    24         sout | xstr(S1A) | "\t\\\\";
    25         sout | xstr(S2) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2;
    26         sout | "\\end{tabular}";
    27         sout | "\\par\\noindent";
    28 
    29         sout | "Aliasing (@`shareEdits@) means that changes flow in both directions; with a simple copy, they do not.";
    30         sout | "\\par\\noindent";
    31         sout | "\\begin{tabular}{llll}";
    32         sout | "\t\t& @s1@\t& @s1a@\t& @s2@\t\\\\";
    33         sout | "\t\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     22
     23        open( outfile, "build/sharing1.tex" );
     24        outfile | "\\begin{cquote}";
     25        outfile | "\\begin{tabular}{@{}llll@{}}";
     26        outfile | "\t\t\t& @s1@\t& @s1a@\t& @s2@\t\\\\";
     27        outfile | xstr(S1) | "\t\\\\";
     28        outfile | xstr(S1A) | "\t\\\\";
     29        outfile | xstr(S2) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2;
     30        outfile | "\\end{tabular}";
     31        outfile | "\\end{cquote}";
     32        close( outfile );
     33
     34//      sout | "Aliasing (@`shareEdits@) means that changes flow in both directions; with a simple copy, they do not.";
     35        open( outfile, "build/sharing2.tex" );
     36        outfile | "\\begin{cquote}";
     37        outfile | "\\begin{tabular}{@{}llll@{}}";
     38        outfile | "\t\t& @s1@\t& @s1a@\t& @s2@\t\\\\";
     39        outfile | "\\multicolumn{1}{r}{initial} & " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    3440
    3541        #define S1s1 s1 [1] = '+'
    3642        S1s1;
    3743        assert( s1 == "a+c" );
    38         sout | xstr(S1s1) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     44        outfile | xstr(S1s1) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    3945
    4046        #define S1As1 s1a[1] = '-'
    4147        S1As1;
    4248        assert( s1a == "a-c" );
    43         sout | xstr(S1As1) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     49        outfile | xstr(S1As1) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    4450
    4551        #define S2s1 s2 [1] = '|'
    4652        S2s1;
    4753        assert( s2 == "a|c" );
    48         sout | xstr(S2s1) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2;
    49         sout | "\\end{tabular}";
    50         sout | "\\par\\noindent";
    51 
    52         sout | "Assignment of a value is just a modificiation."
    53                    "\nThe aliasing relationship is established at construction and is unaffected by assignment of a value.";
    54         sout | "\\par\\noindent";
    55         sout | "\\begin{tabular}{llll}";
    56         sout | "\t\t& @s1@\t& @s1a@\t& @s2@\t\\\\";
    57         sout | "\t\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     54        outfile | xstr(S2s1) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2;
     55        outfile | "\\end{tabular}";
     56        outfile | "\\end{cquote}";
     57        close( outfile );
     58
     59//      sout | "Assignment of a value is just a modificiation."
     60//                 "\nThe aliasing relationship is established at construction and is unaffected by assignment of a value.";
     61        open( outfile, "build/sharing3.tex" );
     62        outfile | "\\begin{cquote}";
     63        outfile | "\\begin{tabular}{llll}";
     64        outfile | "\t\t& @s1@\t& @s1a@\t& @s2@\t\\\\";
     65        outfile | "\\multicolumn{1}{r}{initial} & " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    5866
    5967        #define S1qrs s1  = "qrs"
    6068        S1qrs;
    6169        assert( s1 == "qrs" );
    62         sout | xstr(S1qrs) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     70        outfile | xstr(S1qrs) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    6371
    6472        #define S1Atuv s1a = "tuv"
    6573        S1Atuv;
    6674        assert( s1a == "tuv" );
    67         sout | xstr(S1Atuv) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     75        outfile | xstr(S1Atuv) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    6876
    6977        #define S2wxy s2  = "wxy"
    7078        S2wxy;
    7179        assert( s2 == "wxy" );
    72         sout | xstr(S2wxy) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2;
    73         sout | "\\end{tabular}";
    74         sout | "\\par\\noindent";
    75 
    76         sout | "Assignment from a string is just assignment of a value."
    77                    "\nWhether of not the RHS participates in aliasing is irrelevant.  Any aliasing of the LHS is unaffected.";
    78         sout | "\\par\\noindent";
    79         sout | "\\begin{tabular}{llll}";
    80         sout | "\t\t& @s1@\t& @s1a@\t& @s2@\t\\\\";
    81         sout | "\t\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     80        outfile | xstr(S2wxy) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2;
     81        outfile | "\\end{tabular}";
     82        outfile | "\\end{cquote}";
     83        close( outfile );
     84
     85//      sout | "Assignment from a string is just assignment of a value."
     86//                 "\nWhether of not the RHS participates in aliasing is irrelevant.  Any aliasing of the LHS is unaffected.";
     87        open( outfile, "build/sharing4.tex" );
     88        outfile | "\\begin{cquote}";
     89        outfile | "\\begin{tabular}{llll}";
     90        outfile | "\t\t& @s1@\t& @s1a@\t& @s2@\t\\\\";
     91        outfile | "\\multicolumn{1}{r}{initial} & " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    8292
    8393        #define S1S2 s1  = s2
     
    8696        assert( s1a == "wxy" );
    8797        assert( s2 == "wxy" );
    88         sout | xstr(S1S2) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     98        outfile | xstr(S1S2) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    8999
    90100        #define S1aaa s1  = "aaa"
     
    93103        assert( s1a == "aaa" );
    94104        assert( s2 == "wxy" );
    95         sout | xstr(S1aaa) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     105        outfile | xstr(S1aaa) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    96106
    97107        #define S2S1 s2  = s1
     
    100110        assert( s1a == "aaa" );
    101111        assert( s2 == "aaa" );
    102         sout | xstr(S2S1) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     112        outfile | xstr(S2S1) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    103113
    104114        #define S2bbb s2  = "bbb"
     
    107117        assert( s1a == "aaa" );
    108118        assert( s2 == "bbb" );
    109         sout | xstr(S2bbb) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    110      
    111     #define S2S1a s2  = s1a
     119        outfile | xstr(S2bbb) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     120
     121        #define S2S1a s2  = s1a
    112122        S2S1a;
    113123        assert( s1 == "aaa" );
    114124        assert( s1a == "aaa" );
    115125        assert( s2 == "aaa" );
    116         sout | xstr(S2S1a) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     126        outfile | xstr(S2S1a) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    117127
    118128        #define S2ccc s2  = "ccc"
     
    121131        assert( s1a == "aaa" );
    122132        assert( s2 == "ccc" );
    123         sout | xstr(S2ccc) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    124      
     133        outfile | xstr(S2ccc) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     134
    125135        #define S1xxx s1  = "xxx"
    126136        S1xxx;
     
    128138        assert( s1a == "xxx" );
    129139        assert( s2 == "ccc" );
    130         sout | xstr(S1xxx) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
    131         sout | "\\end{tabular}";
    132         sout | "\\par";
     140        outfile | xstr(S1xxx) | "\t& " | s1 | "\t& " | s1a | "\t& " | s2 | "\t\\\\";
     141        outfile | "\\end{tabular}";
     142        outfile | "\\end{cquote}";
     143        close( outfile );
    133144}
    134145
    135146
    136147void demo2() {
    137         sout | "Consider new strings @s1_mid@ being an alias for a run in the middle of @s1@, along with @s2@, made by a simple copy from the middle of @s1@.";
    138         sout | "\\par\\noindent";
    139         sout | "\\begin{tabular}{llll}";
    140         sout | "\t\t\t\t& @s1@\t& @s1_mid@\t& @s2@\t\\\\";
     148//      sout | "Consider new strings @s1_mid@ being an alias for a run in the middle of @s1@, along with @s2@, made by a simple copy from the middle of @s1@.";
     149        open( outfile, "build/sharing5.tex" );
     150        outfile | "\\begin{cquote}";
     151        outfile | "\\begin{tabular}{llll}";
     152        outfile | "\t\t\t\t& @s1@\t& @s1_mid@\t& @s2@\t\\\\";
    141153
    142154        #define D2_s1_abcd string s1     = "abcd"
    143155        D2_s1_abcd;
    144         sout | xstr(D2_s1_abcd) | "\t\\\\";
     156        outfile | xstr(D2_s1_abcd) | "\t\\\\";
    145157
    146158        #define D2_s1mid_s1 string s1_mid = s1(1,2)`shareEdits
    147159        D2_s1mid_s1;
    148         sout | xstr(D2_s1mid_s1) | "\t\\\\";
     160        outfile | xstr(D2_s1mid_s1) | "\t\\\\";
    149161
    150162        #define D2_s2_s1 string s2     = s1(1,2)
    151         D2_s2_s1;     
     163        D2_s2_s1;
    152164        assert( s1 == "abcd" );
    153165        assert( s1_mid == "bc" );
    154166        assert( s2 == "bc" );
    155         sout | xstr(D2_s2_s1) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
    156         sout | "\\end{tabular}";
    157         sout | "\\par\\noindent";
    158 
    159     sout | "Again, @`shareEdits@ passes changes in both directions; copy does not.  Note the difference in index values, with the \\emph{b} position being 1 in the longer string and 0 in the shorter strings.  In the case of s1 aliasing with @s1_mid@, the very same character is being accessed by different postitions.";
    160         sout | "\\par\\noindent";
    161         sout | "\\begin{tabular}{llll}";
    162         sout | "\t\t\t\t& @s1@\t& @s1_mid@\t& @s2@\t\\\\";
    163         sout | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
     167        outfile | xstr(D2_s2_s1) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
     168        outfile | "\\end{tabular}";
     169        outfile | "\\end{cquote}";
     170        close( outfile );
     171
     172//      sout | "Again, @`shareEdits@ passes changes in both directions; copy does not.  Note the difference in index values, with the \\emph{b} position being 1 in the longer string and 0 in the shorter strings.  In the case of s1 aliasing with @s1_mid@, the very same character is being accessed by different postitions.";
     173        open( outfile, "build/sharing6.tex" );
     174        outfile | "\\begin{cquote}";
     175        outfile | "\\begin{tabular}{llll}";
     176        outfile | "\t\t\t\t& @s1@\t& @s1_mid@\t& @s2@\t\\\\";
     177        outfile | "\\multicolumn{1}{r}{initial} & " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
    164178
    165179        #define D2_s1_plus s1    [1] = '+'
     
    168182        assert( s1_mid == "+c" );
    169183        assert( s2 == "bc" );
    170         sout | xstr(D2_s1_plus) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
     184        outfile | xstr(D2_s1_plus) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
    171185
    172186        #define D2_s1mid_minus s1_mid[0] = '-'
     
    175189        assert( s1_mid == "-c" );
    176190        assert( s2 == "bc" );
    177         sout | xstr(D2_s1mid_minus) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
    178      
    179     #define D2_s2_pipe s2    [0] = '|'
     191        outfile | xstr(D2_s1mid_minus) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
     192
     193        #define D2_s2_pipe s2    [0] = '|'
    180194        D2_s2_pipe;
    181195        assert( s1 == "a-cd" );
    182196        assert( s1_mid == "-c" );
    183197        assert( s2 == "|c" );
    184         sout | xstr(D2_s2_pipe) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
    185         sout | "\\end{tabular}";
    186         sout | "\\par\\noindent";
    187 
    188     sout | "Once again, assignment of a value is a modificiation that flows through the aliasing relationship, without affecting its structure.";
    189         sout | "\\par\\noindent";
    190         sout | "\\begin{tabular}{llll}";
    191         sout | "\t\t\t\t& @s1@\t& @s1_mid@\t& @s2@\t\\\\";
    192         sout | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
     198        outfile | xstr(D2_s2_pipe) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
     199        outfile | "\\end{tabular}";
     200        outfile | "\\end{cquote}";
     201        close( outfile );
     202
     203//      sout | "Once again, assignment of a value is a modificiation that flows through the aliasing relationship, without affecting its structure.";
     204        open( outfile, "build/sharing7.tex" );
     205        outfile | "\\begin{cquote}";
     206        outfile | "\\begin{tabular}{llll}";
     207        outfile | "\t\t\t\t& @s1@\t& @s1_mid@\t& @s2@\t\\\\";
     208        outfile | "\\multicolumn{1}{r}{initial} & " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
    193209
    194210        #define D2_s1mid_ff s1_mid = "ff"
     
    197213        assert( s1_mid == "ff" );
    198214        assert( s2 == "|c" );
    199         sout | xstr(D2_s1mid_ff) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
    200      
     215        outfile | xstr(D2_s1mid_ff) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
     216
    201217        #define D2_s2_gg s2     = "gg"
    202218        D2_s2_gg;
     
    204220        assert( s1_mid == "ff" );
    205221        assert( s2 == "gg" );
    206         sout | xstr(D2_s2_gg) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
    207         sout | "\\end{tabular}";
    208         sout | "\\par\\noindent";
    209 
    210     sout | "In the \\emph{ff} step, which is a positive example of flow across an aliasing relationship, the result is straightforward to accept because the flow direction is from contained (small) to containing (large).  The following rules for edits through aliasing substrings will guide how to flow in the opposite direction.";
    211         sout | "\\par";
    212 
    213 
    214     sout | "Growth and shrinkage are natural extensions.  An empty substring is a real thing, at a well-defined location, whose meaning is extrapolated from the examples so far.  The intended metaphor is to operating a GUI text editor.  Having an aliasing substring is like using the mouse to select a few words.  Assigning onto an aliasign substring is like typing from having a few words selected:  depending how much you type, the file being edited can get shorter or longer.";
    215         sout | "\\par\\noindent";
    216         sout | "\\begin{tabular}{lll}";
    217         sout | "\t\t\t\t& @s1@\t& @s1_mid@\t\\\\";
    218         sout | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
     222        outfile | xstr(D2_s2_gg) | "\t& " | s1 | "\t& " | s1_mid | "\t& " | s2 | "\t\\\\";
     223        outfile | "\\end{tabular}";
     224        outfile | "\\end{cquote}";
     225        close( outfile );
     226
     227//      sout | "In the \\emph{ff} step, which is a positive example of flow across an aliasing relationship, the result is straightforward to accept because the flow direction is from contained (small) to containing (large).  The following rules for edits through aliasing substrings will guide how to flow in the opposite direction.";
     228//      sout | "\\par";
     229
     230
     231//      sout | "Growth and shrinkage are natural extensions.  An empty substring is a real thing, at a well-defined location, whose meaning is extrapolated from the examples so far.  The intended metaphor is to operating a GUI text editor.  Having an aliasing substring is like using the mouse to select a few words.  Assigning onto an aliasign substring is like typing from having a few words selected:  depending how much you type, the file being edited can get shorter or longer.";
     232        open( outfile, "build/sharing8.tex" );
     233        outfile | "\\begin{cquote}";
     234        outfile | "\\begin{tabular}{lll}";
     235        outfile | "\t\t\t\t& @s1@\t& @s1_mid@\t\\\\";
     236        outfile | "\\multicolumn{1}{r}{initial} & " | s1 | "\t& " | s1_mid | "\t\\\\";
    219237
    220238        assert( s1 == "affd" );
    221 //      assert( s1_mid == "fc" );                                                    // ????????? bug?
    222         sout | xstr(D2_s2_gg) | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
     239//      assert( s1_mid == "fc" );                                                                                                        // ????????? bug?
     240        outfile | xstr(D2_s2_gg) | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
    223241
    224242        #define D2_s1mid_hhhh s1_mid = "hhhh"
     
    226244        assert( s1 == "ahhhhd" );
    227245        assert( s1_mid == "hhhh" );
    228         sout  | xstr(D2_s1mid_hhhh)  | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
    229      
     246        outfile  | xstr(D2_s1mid_hhhh)  | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
     247
    230248        #define D2_s1mid_i s1_mid = "i"
    231249        D2_s1mid_i;
    232250        assert( s1 == "aid" );
    233251        assert( s1_mid == "i" );
    234         sout  | xstr(D2_s1mid_i)  | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
     252        outfile  | xstr(D2_s1mid_i)  | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
    235253
    236254        #define D2_s1mid_empty s1_mid = ""
     
    238256        assert( s1 == "ad" );
    239257        // assert( s1_mid == "" );    ------ Should be so, but fails
    240         sout  | xstr(D2_s1mid_empty)  | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
     258        outfile  | xstr(D2_s1mid_empty)  | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
    241259
    242260        #define D2_s1mid_jj s1_mid = "jj"
     
    244262        assert( s1 == "ajjd" );
    245263        assert( s1_mid == "jj" );
    246         sout  | xstr(D2_s1mid_jj)  | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
    247         sout | "\\end{tabular}";
    248         sout | "\\par\\noindent";
    249 
    250     sout | "Multiple portions can be aliased.  When there are several aliasing substrings at once, the text editor analogy becomes an online multi-user editor.  I should be able to edit a paragraph in one place (changing the document's length), without my edits affecting which letters are within a mouse-selection that you had made previously, somewhere else.";
    251         sout | "\\par\\noindent";
    252         sout | "\\begin{tabular}{lllll}";
    253         sout | "\t\t\t\t& @s1@\t& @s1_bgn@\t& @s1_mid@\t& @s1_end@\t\\\\";
     264        outfile  | xstr(D2_s1mid_jj)  | "\t& " | s1 | "\t& " | s1_mid | "\t\\\\";
     265        outfile | "\\end{tabular}";
     266        outfile | "\\end{cquote}";
     267        close( outfile );
     268
     269//      sout | "Multiple portions can be aliased.  When there are several aliasing substrings at once, the text editor analogy becomes an online multi-user editor.  I should be able to edit a paragraph in one place (changing the document's length), without my edits affecting which letters are within a mouse-selection that you had made previously, somewhere else.";
     270        open( outfile, "build/sharing9.tex" );
     271        outfile | "\\begin{cquote}";
     272        outfile | "\\begin{tabular}{lllll}";
     273        outfile | "\t\t\t\t& @s1@\t& @s1_bgn@\t& @s1_mid@\t& @s1_end@\t\\\\";
    254274
    255275        #define D2_s1bgn_s1     string s1_bgn = s1(0, 1)`shareEdits
    256276        D2_s1bgn_s1;
    257         sout  | xstr(D2_s1bgn_s1)  | "\t\\\\";
     277        outfile  | xstr(D2_s1bgn_s1)  | "\t\\\\";
    258278
    259279        #define D2_s1end_s1 string s1_end = s1(3, 1)`shareEdits
     
    263283        assert( s1_mid == "jj" );
    264284        assert( s1_end == "d" );
    265         sout  | xstr(D2_s1end_s1)  | "\t& " | s1 | "\t& " | s1_bgn | "\t& " | s1_mid | "\t& " | s1_end | "\t\\\\";
    266      
     285        outfile  | xstr(D2_s1end_s1)  | "\t& " | s1 | "\t& " | s1_bgn | "\t& " | s1_mid | "\t& " | s1_end | "\t\\\\";
     286
    267287        #define D1_s1bgn_zzz s1_bgn = "zzzz"
    268288        D1_s1bgn_zzz;
     
    271291        assert( s1_mid == "jj" );
    272292        assert( s1_end == "d" );
    273         sout  | xstr(D1_s1bgn_zzz)  | "\t& " | s1 | "\t& " | s1_bgn | "\t& " | s1_mid | "\t& " | s1_end | "\t\\\\";
    274         sout | "\\end{tabular}";
    275         sout | "\\par\\noindent";
    276 
    277     sout | "When an edit happens on an aliasing substring that overlaps another, an effect is unavoidable.  Here, the passive party sees its selection shortened, to exclude the characters that were not part of the original selection.";
    278         sout | "\\par\\noindent";
    279         sout | "\\begin{tabular}{llllll}";
    280         sout | "\t\t\t\t& @s1@\t& @s1_bgn@\t& @s1_crs@\t& @s1_mid@\t& @s1_end@\t\\\\";
     293        outfile  | xstr(D1_s1bgn_zzz)  | "\t& " | s1 | "\t& " | s1_bgn | "\t& " | s1_mid | "\t& " | s1_end | "\t\\\\";
     294        outfile | "\\end{tabular}";
     295        outfile | "\\end{cquote}";
     296        close( outfile );
     297
     298//      sout | "When an edit happens on an aliasing substring that overlaps another, an effect is unavoidable.  Here, the passive party sees its selection shortened, to exclude the characters that were not part of the original selection.";
     299        open( outfile, "build/sharing10.tex" );
     300        outfile | "\\begin{cquote}";
     301        outfile | "\\begin{tabular}{llllll}";
     302        outfile | "\t\t\t\t& @s1@\t& @s1_bgn@\t& @s1_crs@\t& @s1_mid@\t& @s1_end@\t\\\\";
    281303
    282304        #define D2_s1crs_s1 string s1_crs = s1(3, 2)`shareEdits
     
    286308        assert( s1_crs == "zj" );
    287309        assert( s1_mid == "jj" );
    288         assert( s1_end == "d" ); 
    289         sout  | xstr(D2_s1crs_s1)  | "\t& " | s1 | "\t& " | s1_bgn | "\t& " | s1_crs | "\t& " | s1_mid | "\t& " | s1_end | "\t\\\\";
     310        assert( s1_end == "d" );
     311        outfile  | xstr(D2_s1crs_s1)  | "\t& " | s1 | "\t& " | s1_bgn | "\t& " | s1_crs | "\t& " | s1_mid | "\t& " | s1_end | "\t\\\\";
    290312
    291313        #define D2_s1crs_ppp s1_crs = "+++"
     
    296318        assert( s1_mid == "j" );
    297319        assert( s1_end == "d" );
    298         sout  | xstr(D2_s1crs_ppp)  | "\t& " | s1 | "\t& " | s1_bgn | "\t& " | s1_crs | "\t& " | s1_mid | "\t& " | s1_end | "\t\\\\";
    299         sout | "\\end{tabular}";
    300         sout | "\\par\\noindent";
    301         sout | "TODO: finish typesetting the demo";
    302 
    303     // "This shortening behaviour means that a modification has to occur entirely inside a substring, to show up in that substring.  Sharing changes through the intersection of partially overlapping aliases is still possible, so long as the receiver's boundary is not inside the edit."
     320        outfile  | xstr(D2_s1crs_ppp)  | "\t& " | s1 | "\t& " | s1_bgn | "\t& " | s1_crs | "\t& " | s1_mid | "\t& " | s1_end | "\t\\\\";
     321        outfile | "\\end{tabular}";
     322        outfile | "\\end{cquote}";
     323        close( outfile );
     324
     325        // "This shortening behaviour means that a modification has to occur entirely inside a substring, to show up in that substring.  Sharing changes through the intersection of partially overlapping aliases is still possible, so long as the receiver's boundary is not inside the edit."
    304326
    305327        string word = "Phi";
     
    309331        assert( consonants == "Ph" );
    310332        assert( miniscules == "hi" );
    311      
     333
    312334        consonants[1] = 's';
    313335        assert( word == "Psi" );
     
    321343        string greet_bgn = all(10,1)`shareEdits;
    322344        string greet_end = all(14,1)`shareEdits;
    323      
     345
    324346        assert( all == "They said hello again" );
    325347        assert( greet == "hello" );
    326348        assert( greet_bgn == "h" );
    327349        assert( greet_end == "o" );
    328      
     350
    329351
    330352        greet = "sup";
     
    333355        // assert( greet_bgn == "" );    ------ Should be so, but fails
    334356        // assert( greet_end == "" );
    335      
    336 
    337  
    338 
    339  
    340     /* As in the earlier step where \emph{aj} becomes \emph{ajjd}, such empty substrings maintain their places in the total string, and can be used for filling it.  Because @greet_bgn@ was orginally at the start of the edit, in the outcome, the empty @greet_bgn@ sits just before the written value.  Similarly @greed_end@ goes after.  Though not shown, an overwritten substring at neither side goes arbitrarily to the before side. */
    341  
    342 
    343  
    344 
    345         greet_bgn = "what"; 
    346      
    347      
     357
     358
     359
     360
     361
     362        /* As in the earlier step where \emph{aj} becomes \emph{ajjd}, such empty substrings maintain their places in the total string, and can be used for filling it.  Because @greet_bgn@ was orginally at the start of the edit, in the outcome, the empty @greet_bgn@ sits just before the written value.  Similarly @greed_end@ goes after.  Though not shown, an overwritten substring at neither side goes arbitrarily to the before side. */
     363
     364
     365
     366
     367        greet_bgn = "what";
     368
     369
    348370        assert( all == "They said whatsup again" );
    349      
     371
    350372        assert( greet == "sup" );
    351      
     373
    352374        assert( greet_bgn == "what" );
    353375        // assert( greet_end == "" );    ------ Should be so, but fails
    354      
    355 
    356         greet_end = "..."; 
    357      
    358      
     376
     377
     378        greet_end = "...";
     379
     380
    359381        assert( all == "They said whatsup... again" );
    360      
     382
    361383        assert( greet == "sup" );
    362      
     384
    363385        assert( greet_bgn == "what" );
    364      
     386
    365387        assert( greet_end == "..." );
    366      
    367 
    368  
    369 
    370  
    371     /* Though these empty substrings hold their places in the total string, an empty string only belongs to bigger strings when it occurs completely inside them.  There is no such state as including an empty substring at an edge.  For this reason, @word@ gains the characters added by assigning to @greet_bgn@ and @greet_end@, but the string @greet@ does not. */
    372  
     388
     389
     390
     391
     392
     393        /* Though these empty substrings hold their places in the total string, an empty string only belongs to bigger strings when it occurs completely inside them.  There is no such state as including an empty substring at an edge.  For this reason, @word@ gains the characters added by assigning to @greet_bgn@ and @greet_end@, but the string @greet@ does not. */
     394
    373395
    374396}
     
    377399int main(int argc, char ** argv) {
    378400
    379     demo1();
    380     demo2();
    381     printf("%% %s done running\n", argv[0]);
     401        demo1();
     402        demo2();
     403//      printf("%% %s done running\n", argv[0]);
    382404}
  • doc/theses/mike_brooks_MMath/string.tex

    rb006c51e r10a9479d  
    55
    66
    7 \section{Logical overlap}
    8 
    9 \input{sharing-demo.tex}
     7\section{String Operations}
     8
     9To prepare for the following discussion, a simple comparison among C, \CC, and \CFA basic string operation is presented.
     10\begin{cquote}
     11\begin{tabular}{@{}l|l|l@{}}
     12C @char [ ]@                    &  \CC @string@                 & \CFA @string@ \\
     13\hline
     14@strcpy@, @strncpy@             & @=@                                   & @=@   \\
     15@strcat@, @strncat@             & @+@                                   & @+@   \\
     16@strcmp@, @strncmp@             & @==@, @!=@, @<@, @<=@, @>@, @>=@ & @==@, @!=@, @<@, @<=@, @>@, @>=@ \\
     17@strlen@                                & @length@                              & @size@        \\
     18@[ ]@                                   & @[ ]@                                 & @[ ]@ \\
     19                                                & @substr@                              & @substr@      \\
     20                                                & @replace@                             & @=@ \emph{(on a substring)}\\
     21@strstr@                                & @find@, @rfind@               & @find@, MISSING \\
     22@strcspn@                               & @find_first_of@, @find_last_of@ & @include@, MISSING \\
     23@strspn@                                & @find_first_not_of@, @find_last_not_of@ & @exclude@, MISSING \\
     24                                                & @c_str@                               & MISSING \\
     25\end{tabular}
     26\end{cquote}
     27The key commonality is that operations work on groups of characters for assigning. copying, scanning, and updating.
     28Because a C string is null terminated and requires explicit storage management \see{\VRef{s:String}}, most of its group operations are error prone and expensive.
     29Most high-level string libraries use a separate length field and specialized storage management to support group operations.
     30\CC strings retain null termination to interface with library functions requiring C strings.
     31\begin{cfa}
     32int open( const char * pathname, int flags );
     33string fname{ "test.cc" );
     34open( fname.@c_str()@ );
     35\end{cfa}
     36The function @c_str@ does not create a new null-terminated C string from the \CC string, as that requires passing ownership of the C string to the caller for eventual deletion.\footnote{
     37C functions like \lstinline{strdup} do return allocated storage that must be freed by the caller.}
     38Instead, each \CC string is null terminator just in case it might be needed for this purpose.
     39Providing this backwards compatibility with C has a ubiquitous performance and storage cost.
     40
     41
     42\section{Storage Management}
     43
     44This section discusses issues related to storage management of strings.
     45Specifically, it is common for strings to logically overlap completely or partially.
     46\begin{cfa}
     47string s1 = "abcdef";
     48string s2 = s1; $\C{// complete overlap, s2 == "abcdef"}$
     49string s3 = s1.substr( 0, 3 ); $\C{// partial overlap, s3 == "abc"}$
     50\end{cfa}
     51This raises the question of how strings behave when an overlapping component is changed,
     52\begin{cfa}
     53s3[1] = 'w'; $\C{// what happens to s1 and s2?}$
     54\end{cfa}
     55This question is the notion of mutable or immutable strings.
     56For example, Java has immutable strings that are copied when any overlapping string changes.
     57Note, the notion of underlying string mutability is not specified by @const@, \eg:
     58\begin{cfa}
     59const string s1 = "abc";
     60\end{cfa}
     61Here, @const@ applies to the @s1@ pointer to @"abc"@, and @"abc"@ is an immutable constant that is \emph{copied} into the string's storage.
     62Hence, @s1@ is not pointing at an immutable constant, meaning its underlying string is always mutable, unless some other designation is specified, such as Java's global rule.
     63
     64
     65\subsection{Logical overlap}
     66
     67\CFA provides a dynamic mechanism to indicate mutable or immutable as an assignment attribute: @`shareEdits@.
    1068
    1169Consider two strings @s1@ and @s1a@ that are in an aliasing relationship, and a third, @s2@, made by a simple copy from @s1@.
    12 \par\noindent
    13 \begin{tabular}{llll}
    14                                 & @s1@  & @s1a@ & @s2@  \\
    15 %\input{sharing-demo1.tex}
    16 \end{tabular}
    17 \par\noindent
     70Aliasing (@`shareEdits@) means that changes flow in both directions; with a simple copy, they do not.
     71\input{sharing1.tex}
     72
     73Aliasing (@`shareEdits@) means that changes flow in both directions; with a simple copy, they do not.
     74\input{sharing2.tex}
     75
     76Assignment of a value is just a modification.
     77The aliasing relationship is established at construction and is unaffected by assignment of a value.
     78\input{sharing3.tex}
     79
     80Assignment from a string is just assignment of a value.
     81Whether of not the RHS participates in aliasing is irrelevant.  Any aliasing of the LHS is unaffected.
     82\input{sharing4.tex}
     83
     84Consider new strings @s1_mid@ being an alias for a run in the middle of @s1@, along with @s2@, made by a simple copy from the middle of @s1@.
     85\input{sharing5.tex}
     86
     87Again, @`shareEdits@ passes changes in both directions; copy does not.
     88Note the difference in index values, with the \emph{b} position being 1 in the longer string and 0 in the shorter strings.
     89In the case of s1 aliasing with @s1_mid@, the very same character is being accessed by different positions.
     90\input{sharing6.tex}
     91
     92Once again, assignment of a value is a modification that flows through the aliasing relationship, without affecting its structure.
     93\input{sharing7.tex}
     94
     95In the \emph{ff} step, which is a positive example of flow across an aliasing relationship, the result is straightforward to accept because the flow direction is from contained (small) to containing (large).
     96The following rules for edits through aliasing substrings will guide how to flow in the opposite direction.
     97
     98Growth and shrinkage are natural extensions.
     99An empty substring is a real thing, at a well-defined location, whose meaning is extrapolated from the examples so far.
     100The intended metaphor is to operating a GUI text editor.
     101Having an aliasing substring is like using the mouse to select a few words.
     102Assigning onto an aliasing substring is like typing from having a few words selected: depending how much you type, the file being edited can get shorter or longer.
     103\input{sharing8.tex}
     104
     105Multiple portions can be aliased.
     106When there are several aliasing substrings at once, the text editor analogy becomes an online multi-user editor.
     107I should be able to edit a paragraph in one place (changing the document's length), without my edits affecting which letters are within a mouse-selection that you had made previously, somewhere else.
     108\input{sharing9.tex}
     109
     110When an edit happens on an aliasing substring that overlaps another, an effect is unavoidable.
     111Here, the passive party sees its selection shortened, to exclude the characters that were not part of the original selection.
     112\input{sharing10.tex}
     113
     114TODO: finish typesetting the demo
     115
     116%\input{sharing-demo.tex}
    18117
    19118
    20119\subsection{RAII limitations}
    21120
    22 Earlier work on \CFA [to cite Schluntz] implemented the feature of constructors and destructors.  A constructor is a user-defined function that runs implicitly, when control passes an object's declaration, while a destructor runs at the exit of the declaration's lexical scope.  The feature allows programmers to assume that, whenever a runtime object of a certain type is accessible, the system called one of the programmer's constructor functions on that object, and a matching destructor call will happen in the future.  The feature helps programmers know that their programs' invariants obtain.
    23 
    24 The purposes of such invariants go beyond ensuring authentic values for the bits inside the object.   These invariants can track occurrences of the managed objects in other data structures.  Reference counting is a typical application of the latter invariant type.  With a reference-counting smart pointer, the constructor and destructor \emph{of the pointer type} track the life cycles of occurrences of these pointers, by incrementing and decrementing a counter (usually) on the referent object, that is, they maintain a that is state separate from the objects to whose life cycles they are attached.  Both the \CC and \CFA RAII systems ares powerful enough to achieve such reference counting.
    25 
    26 The \CC RAII system supports a more advanced application.  A life cycle function has access to the object under management, by location; constructors and destuctors receive a @this@ parameter providing its memory address.  A lifecycle-function implementation can then add its objects to a collection upon creation, and remove them at destruction.  A modulue that provides such objects, by using and encapsulating such a collection, can traverse the collection at relevant times, to keep the objects ``good.''  Then, if you are the user of such an module, declaring an object of its type means not only receiving an authentically ``good'' value at initialization, but receiving a subscription to a service that will keep the value ``good'' until you are done with it.
    27 
    28 In many cases, the relationship between memory location and lifecycle is simple.  But with stack-allocated objects being used as parameters and returns, there is a sender version in one stack frame and a receiver version in another.  \CC is able to treat those versions as distinct objects and guarantee a copy-constructor call for communicating the value from one to the other.  This ability has implications on the language's calling convention.  Consider an ordinary function @void f( Vehicle x )@, which receives an aggregate by value.  If the type @Vehicle@ has custom lifecycle functions, then a call to a user-provided copy constructor occurs, after the caller evaluates its argument expression, after the callee's stack frame exists, with room for its variable @x@ (which is the location that the copy-constructor must target), but before the user-provided body of @f@ begins executing.  \CC achieves this ordering by changing the function signature, in the compiled form, to pass-by-reference and having the callee invoke the copy constructor in its preamble.  On the other hand, if @Vehicle@ is a simple structure then the C calling convention is applied as the code originally appeared, that is, the callsite implementation code performs a bitwise copy from the caller's expression result, into the callee's x.
    29 
    30 TODO: learn correction to fix inconcsistency: this discussion says the callee invokes the copy constructor, but only the caller knows which copy constructor to use!
    31 
    32 TODO: discuss the return-value piece of this pattern
    33 
    34 The \CFA RAII system has limited support for using lifecycle functions to provide a ``stay good'' service.  It works in restricted settings, including on dynamically allocated objects.  It does not work for communicating arguments and returns by value because the system does not produce a constructor call that tracks the implied move from a sender frame to a reciver frame.  This limitation does not prevent a typical reference-counting design from using call-with-value/return-of-value, because the constructor--destructor calls are correctly balanced.  But it impedes a ``stay-good'' service from supporting call-with-value/return-of-value, because the lifecycles presented to the constructor/destor calls do not keep stable locations.  A ``stay-good'' service is acheivable so long as call-with-value/return-of-value do not occur.  The original presentation [to cite Schluntz section] acknoweledges this limitiation; the present discussion makes its consequences more apparent.
    35 
    36 The \CFA team sees this limitation as part of a tactical interem state that should some day be improved.  The \CFA compiler is currently a source-to-source translator that targets relativly portable C.  Several details of its features are provisionally awkward or under-performant until finer control of its code generation is feasible.  In the present state, all calls that appear in \CFA source code as call-with-value/return-of-value are emitted this way to the underlying C calling convention.  SO WHAT?
    37 
    38 The present string-API contribution has both the ``stay good'' promise and call-with-value/return-of-value being essential.  The main string API uses a work-around to acheive the full feature set, at a runtime performance penalty.  An alternative API sacrifices call-with-value/return-of-value functionality to recover full runtime performance.  These APIs are layered, with the slower, friendlier High Level API (HL) wrapping the faster, more primitive Low Level API (LL).  They present the same features, up to lifecycle management, with call-with-value/return-of-value being disabled in LL and implemented with the workaround in HL.  The intention is for most future code to target HL.  In a more distant future state, where \CFA has an RAII system that can handle the problematic quadrant, the HL layer can be abolished, the LL can be renamed to match today's HL, and LL can have its call-with-value/return-of-value permission reenabled.  Then, programs written originally against HL will simply run faster.  In the meantime, two use cases of LL exist.  Performance-critical sections of applications have LL as an option.  Within [Xref perf experiments], though HL-v-LL penalties are measured, typcial comparisons of the contributed string libary vs similar systems are made using LL.  This measurement gives a fair estimate of the goal state for \CFA while it is an evloving work in progress.
    39 
     121Earlier work on \CFA~\cite[ch.~2]{Schluntz17} implemented object constructors and destructors for all types (basic and user defined).
     122A constructor is a user-defined function run implicitly \emph{after} an object's declaration-storage is created, and a destructor is a user-defined function run \emph{before} an object's declaration-storage is deleted.
     123This feature, called RAII~\cite[p.~389]{Stroustrup94}, guarantees pre invariants for users before accessing an object and post invariants for the programming environment after an object terminates.
     124
     125The purposes of these invariants goes beyond ensuring authentic values inside an object.
     126Invariants can also track occurrences of managed objects in other data structures.
     127For example, reference counting is a typical application of an invariant outside of the data values.
     128With a reference-counting smart-pointer, the constructor and destructor \emph{of a pointer type} tracks the life cycle of the object it points to.
     129Both \CC and \CFA RAII systems are powerful enough to achieve reference counting.
     130
     131In general, a lifecycle function has access to an object by location, \ie constructors and destructors receive a @this@ parameter providing an object's memory address.
     132The lifecycle implementation can then add this object to a collection at creation and remove it at destruction.
     133A module providing lifecycle semantics can traverse the collection at relevant times to keep the objects ``good.''
     134Hence, declaring such an object not only ensures ``good'' authentic values, but also an implicit subscription to a service that keeps the value ``good'' across its lifetime.
     135
     136In many cases, the relationship between memory location and lifecycle is straightforward.
     137For example, stack-allocated objects being used as parameters and returns, with a sender version in one stack frame and a receiver version in another, as opposed to assignment where sender and receiver are in the same stack frame.
     138What is crucial for lifecycle management is knowing if the receiver is initialized or uninitialized, \ie an object is or is not currently associated with management.
     139To provide this knowledge, languages differentiate between initialization and assignment to a left-hand side.
     140\begin{cfa}
     141Obj obj2 = obj1;  // initialization, obj2 is uninitialized
     142obj2 = obj1;        // assignment, obj2 must be initialized for management to work
     143\end{cfa}
     144Initialization occurs at declaration by value, parameter by argument, return temporary by function call.
     145Hence, it is necessary to have two kinds of constructors: by value or object.
     146\begin{cfa}
     147Obj obj1{ 1, 2, 3 };  // by value, management is initialized
     148Obj obj2 = obj1;     // by obj, management is updated
     149\end{cfa}
     150When no object management is required, initialization copies the right-hand value.
     151Hence, the calling convention remains uniform, where the unmanaged case uses @memcpy@ as the initialization constructor and managed uses the specified initialization constructor.
     152
     153The \CFA RAII system supports lifecycle functions, except for returning a value from a function to a temporary.
     154For example, in \CC:
     155\begin{cfa}
     156struct S {...};
     157S identity( S s ) { return s; }
     158S s;
     159s = identity( s ); // S temp = identity( s ); s = temp;
     160\end{cfa}
     161the generated code for the function call created a temporary with initialization from the function call, and then assigns the temporary to the receiver.
     162This two step approach means extra storage for the temporary and two copies to get the result into the receiver variable.
     163\CC{17} introduced return value-optimization (RVO)~\cite{RVO20} to ``avoid copying an object that a function returns as its value, including avoiding creation of a temporary object''.
     164\CFA uses C semantics for function return giving direct value-assignment, which eliminates unnecessary code, but skips an essential feature needed by lifetime management.
     165The following discusses the consequences of this semantics with respect to lifetime management of \CFA strings.
     166
     167The present string-API contribution provides lifetime management with initialization semantics on function return.
     168The workaround to achieve the full lifetime semantics does have a runtime performance penalty.
     169An alternative API sacrifices return initialization semantics to recover full runtime performance.
     170These APIs are layered, with the slower, friendlier High Level API (HL) wrapping the faster, more primitive Low Level API (LL).
     171Both API present the same features, up to lifecycle management, with return initialization being disabled in LL and implemented with the workaround in HL.
     172The intention is for most future code to target HL.
     173When \CFA becomes a full compiler, it can provide return initialization with RVO optimizations.
     174Then, programs written with the HL API will simply run faster.
     175In the meantime, performance-critical sections of applications use LL.
     176Subsequent performance experiments~\VRef{s:PerformanceAssessment} with other string libraries has \CFA strings using the LL API.
     177These measurement gives a fair estimate of the goal state for \CFA.
    40178
    41179
    42180\subsection{Memory management}
    43181
    44 A centrepriece of the string module is its memory manager.  The managment scheme defines a large shared buffer for strings' text.  Allocation in this buffer is always bump-pointer; the buffer is compacted and/or relocated with growth when it fills.  A string is a smart pointer into this buffer.
    45 
    46 This cycle of frequent cheap allocations, interspersed with infrequent expensive compactions, has obvious similarities to a general-purpose memory manager based on garbage collection (GC).  A few differences are noteworthy.  First, in a general purpose manager, the objects of allocation contain pointers to other such objects, making the transitive reachability of these objects be a critical property.  Here, the allocations are of buffers of text, never pointers, so one allocation never keeps another one alive.  Second, in a general purpose manager, where the handle that keeps an allocation alive is the same as the program's general-purpose inter-object reference, an extremely lean representation of this reference is required.  Here, a fatter representation is acceptable because [why??].
    47 
    48 
    49 Figure [memmgr-basix.vsdx] shows the representation.  A heap header, with its text buffer, defines a sharing context.  Often, one global sharing context is appropriate for an entire program; exceptions are discussed in [xref TBD].  Strings are handles into the buffer.  They are members of a linked list whose order matches the order of their buffer fragments (exactly, where there is no overlapping, and approximately, where there is).  The header maintains a next-allocation pointer (alloc, in the figure) after the last live allocation of the buffer.  No external references into the buffer are allowed and the management procedure relocates the text allocations as needed.  The string handles contain explicit length fields, null termination characters are not used and all string text is kept in contiguous storage.  When strings (the inter-linked hanldes) are allocated on the program's call stack, a sustained period with no use of the program's dynamic memory allocator can ensue, during which the program nonetheless creates strings, destroys them, and runs length-increasing modifications on existing ones. 
    50 
    51 Compaction happens when the heap fills.  It is the first of two uses of the linked list.  The list allows discovering all live string handles, and from them, the ranges of the character buffer that are in use.  With these ranges known, their total character count gives the amount of space in use.  When that amount is small, compared with the current buffer size, an in-place compaction occurs, which enatils copying the in-use ranges, to be adjacent, at the font of the buffer.  When the in-use amount is large, a larger buffer is allocated (using the program's general-purpose dynamic allcator), the in-use strings are copied to be adjacent at the front of it, and the original buffer is freed back to the program's general allocator.  Either way, navigating the links between the handles provides the pointers into the buffer, first read, to find the source fragment, then written with the location of the resultant fragment.  This linkage across the structure is unaffected during a compaction; only the pointers from the handles to the buffer are modified.  This modification, along with the grooming/provisioning of the text storage resouce that it represents, is an example, in the language of [xref RAII limitations] of the string module providing a ``stay good'' service.
    52 
    53 Object lifecycle events are the subscription-management triggers in such a service.  There are two fundamental string-creation routines:  importing from external text like a C-string, and initialization from an existing \CFA string.  When importing, a fresh allocation at the free end fo the buffer occurs, into which the text is copied.  The resultant handle is therefore inserted into the list at the position after the incumbent last handle, a position given by the heap manager's ``last handle'' pointer.  When initializing from text already on the \CFA heap, the resultant handle is a second reference onto the original run of characters.  In this case, the resultant handle's linked-list position is beside the original handle.  Both string initialization styles preserve the string module's internal invriant that the linked-list order match the buffer order.  For string destruction, the list being doubly linked provides for easy removal of the disappearing handle.
    54 
    55 While a string handle is live, it accepts modification operations, some of which make it reference a different portion of the underlying buffer, and accordingly, move the handle to a different position in the inter-handle list.   While special cases have more optimal handling, the general case requires a fresh buffer run.  In this case, the new run is allocated at the bump-pointer end and filled with the required value.  Then, handles that originally referenced the old location and need to see the new value are pointed at the new buffer location, unlinked from their original positions in the handles' list, and linked in at the end of the list.  An optimal case, when the target is not a substring of something larger, and the source is text from elsewhere in the managed buffer, allows the target to be re-pointed at the source characters, and accordingly, move list position to be beside the source.  Cases where in-place editing happens, addressed further in [xref: TBD], leave affected handles in their original list positions.  In analogy to the two cases of string initialization, the two cases of realizing assignment by moving either to a fresh buffer run, or to overlap references with the source, maintain the invariant of linked list order matching buffer order.
    56 
    57 
    58 To explain: GCing allocator doing bump-pointer with compaction
    59 
    60 
    61 
    62 At the level of the memory manager, these modifications can aways be explained as assignments; for example, an append is an assignemnt into the empty substring at the end.
    63 
    64 While favourable conditions allow for in-place editing, the general case requires a fresh buffer run.  For example, if the new value does not fit in the old place, or if other handles are still using the old value, then the new value will use a fresh buffer run.
     182A centrepiece of the string module is its memory manager.
     183The management scheme defines a shared buffer for string text.
     184Allocation in this buffer is via a bump-pointer;
     185the buffer is compacted and/or relocated with growth when it fills.
     186A string is a smart pointer into this buffer.
     187
     188This cycle of frequent cheap allocations, interspersed with infrequent expensive compactions, has obvious similarities to a general-purpose memory manager based on garbage collection (GC).
     189A few differences are noteworthy.
     190First, in a general purpose manager, the objects of allocation contain pointers to other such objects, making the transitive reachability of these objects be a critical property.
     191Here, the allocations are text, so one allocation never keeps another alive.
     192Second, in a general purpose manager, the handle that keeps an allocation alive is just a lean pointer.
     193For strings, a fatter representation is acceptable because there are fewer string head pointers versus chained pointers within nodes as for linked containers.
     194
     195\begin{figure}
     196\includegraphics{memmgr-basic}
     197\caption{String memory-management data structures}
     198\label{f:memmgr-basic}
     199\end{figure}
     200
     201\VRef[Figure]{f:memmgr-basic} shows the representation.
     202A heap header and its text buffer, defines a sharing context.
     203Normally, one global sharing context is appropriate for an entire program;
     204exceptions are discussed in [xref TBD].
     205A string is a handle into the buffer and linked into a list.
     206The list is doubly linked for $O(1)$ insertion and removal at any location.
     207Strings are orders n the list by text-buffer address, where there is no overlapping, and approximately, where there is.
     208The header maintains a next-allocation pointer, @alloc@, pointing to the last live allocation of the buffer.
     209No external references point into the buffer and the management procedure relocates the text allocations as needed.
     210A string handle contains an explicit string, while its string is contiguous and not null terminated.
     211The length sets an upper limit on the string size, but is large (4 or 8 bytes).
     212String handles can be allocated in the stack or heap, while the text buffer is large enough with good management so that only one dynamic allocation is necessary for it during program execution.
     213During this period strings can vary in size dynamically.
     214
     215When the text buffer fills, \ie the next new string allocation causes @alloc@ to point beyond the end of the buffer, the strings are compacted.
     216The linked handles define all live strings in the buffer, which indirectly defines the allocated and free space in the buffer.
     217Since the string handles are in (roughly) sorted order, the handle list can be traversed copying the first text to the start of the buffer and subsequent strings after each over.
     218After compaction, if the amount of free storage is still less than the new string allocation, a larger text buffer is heap allocated, the current buffer is copies into the new buffer, and the original buffer is freed.
     219Note, the list of string handles is unaffected during a compaction;
     220only the string pointers are modified to new buffer locations.
     221
     222Object lifecycle events are the subscription-management triggers in such a service.
     223There are two fundamental string-creation routines: importing external text like a C-string or reading a string, and initialization from an existing \CFA string.
     224When importing, storage comes from the end of the buffer, into which the text is copied.
     225The resultant handle is inserted at the end of the handle list to maintain ordering.
     226When initializing from text already in the text buffer, the new handle is a second reference into the original run of characters.
     227In this case, the new handle's linked-list position is after the original handle.
     228Both string initialization styles preserve the string module's internal invariant that the linked-list order matches the buffer order.
     229For string destruction, handles are removed from the list.
     230
     231Certain string operations can results in a subset (substring) of another string.
     232The resulting handle is then place in the correct sorted position in the list, possible with a short linear search to locate the position.
     233For string operations resulting in a new string, that string is allocated at the end of the buffer.
     234For shared-edit strings, handles that originally referenced containing locations need to see the new value at the new buffer location.
     235These strings are moved to appropriate locations at the end of the list (addressed further in [xref: TBD].
     236For nonshared-edit strings, a containing string can be moved and the nonshared strings can remain in the same position.
     237String assignment words similarly to string initialization, maintain the invariant of linked list order matching buffer order.
     238
     239At the level of the memory manager, these modifications can always be explained as assignments; for example, an append is an assignment into the empty substring at the end.
     240
     241While favourable conditions allow for in-place editing, the general case requires a fresh buffer run.
     242For example, if the new value does not fit in the old place, or if other handles are still using the old value, then the new value will use a fresh buffer run.
    65243
    66244where there is room for the resulting value in the original buffer location, and where all handles referring to the original buffer location should see the new value,
    67245
    68 
    69 always boiled down to assignment and appendment.  Assignment has special cases that happen in-place, but in the general case, it is implemented as a sequence of appends onto a fresh allocation at the end of the buffer.  (The sequence has multiple steps when the assignment target is a substring: old before, new middle, old after.)  Similarly, an append request can be serviced in-place when there is room, or as a pair of appends
    70 
     246always boiled down to assignment and appendment.
     247Assignment has special cases that happen in-place, but in the general case, it is implemented as a sequence of appends onto a fresh allocation at the end of the buffer.
     248(The sequence has multiple steps when the assignment target is a substring: old before, new middle, old after.)
     249Similarly, an append request can be serviced in-place when there is room, or as a pair of appends.
    71250
    72251
    73252\subsection{Sharing implementation}
    74253
    75 The \CFA string module has two manners in which serveral string handles can share an unerlying run of characters. 
    76 
    77 The first type of sharing is user-requested, following the [xref Logical Overlap].  Here, the user requests, explicitly, that both handles be views of the same logical, modifiable string.  This state is typically prodecd by the substring operation.  In a typical substring call, the source string-handle is referencing an entire string, and the resluting, newly made, string handle is referencing a portion of the orignal.  In this state, a subsequent modification made by either is visible in both.
    78 
    79 The second type of sharing happens when the system implicitly delays the physical execution of a logical \emph{copy} operation, as part of its copy-on-write optimization.  This state is typically produced by constructing a new string, using an original string as its intialization source.  In this state, a subsequent modification done on one handle triggers the deferred copy action, leaving the handles referencing different runs within the buffer, holding distinct values.
     254The \CFA string module has two manners in which several string handles can share an underlying run of characters. 
     255
     256The first type of sharing is user-requested, following the [xref Logical Overlap].  Here, the user requests, explicitly, that both handles be views of the same logical, modifiable string.  This state is typically produced by the substring operation.  In a typical substring call, the source string-handle is referencing an entire string, and the resulting, newly made, string handle is referencing a portion of the original.  In this state, a subsequent modification made by either is visible in both.
     257
     258The second type of sharing happens when the system implicitly delays the physical execution of a logical \emph{copy} operation, as part of its copy-on-write optimization.  This state is typically produced by constructing a new string, using an original string as its initialization source.  In this state, a subsequent modification done on one handle triggers the deferred copy action, leaving the handles referencing different runs within the buffer, holding distinct values.
    80259
    81260A further abstraction, in the string module's implementation, helps distinguish the two senses of sharing.  A share-edit set (SES) is an equivalence class over string handles, being the reflexive, symmetric and transitive closure of the relationship of one being constructed from the other, with the ``share edits'' opt-in given.  It is represented by a second linked list among the handles.  A string that shares edits with no other is in a SES by itself.  Inside a SES, a logical modification of one substring portion may change the logical value in another, depending on whether the two actually overlap.  Conversely, no logical value change can flow outside of a SES.  Even if a modification on one string handle does not reveal itself \emph{logically} to anther handle in the same SES (because they don't overlap), if the modification is length-changing, completing the modification requires visiting the second handle to adjust its location in the sliding text.
     
    84263\subsection{Avoiding implicit sharing}
    85264
    86 There are tradeoffs associated with the copy-on-write mechanism.  Several quatitative matters are detailed in the [xref: Performance Assessment] section and the qualitiative issue of multi-threaded support is introduced here.  The \CFA sting library provides a switch to disable the sharing mechanism for situtations where it is inappropriate.
     265There are tradeoffs associated with the copy-on-write mechanism.  Several qualitative matters are detailed in the [xref: Performance Assessment] section and the qualitative issue of multi-threaded support is introduced here.  The \CFA sting library provides a switch to disable the sharing mechanism for situations where it is inappropriate.
    87266
    88267Because of the inter-linked string handles, any participant managing one string is also managing, directly, the neighbouring strings, and from there, a data structure of the ``set of all strings.''  This data structure is intended for sequential access.  A negative consequence of this decision is that multiple threads using strings need to be set up so that they avoid attempting to modify (concurrently) an instance of this structure.  A positive consequence is that a single-threaded program, or a program with several independent threads, can use the sharing context without an overhead from locking.
    89268
    90 The \CFA sting library provides the @string_sharectx@ type to control an ambient sharing context for the current thread.  It allows two adjustments: to opt out of sharing entirely, or to begin sharing within a private context.  Either way, the chosen mode applies to the current thread, for the duration of the lifetime of the created  @string_sharectx@ object, up to being suspended by child liftimes of different contexts.  The indended use is with stack-managed lifetimes, in which the established context lasts until the current function returns, and affects all functions called that don't create their own contexts.
    91 \lstinputlisting[language=CFA, firstline=20, lastline=34]{sharectx-demo.cfa}
     269The \CFA sting library provides the @string_sharectx@ type to control an ambient sharing context for the current thread.  It allows two adjustments: to opt out of sharing entirely, or to begin sharing within a private context.  Either way, the chosen mode applies to the current thread, for the duration of the lifetime of the created  @string_sharectx@ object, up to being suspended by child lifetimes of different contexts.  The indented use is with stack-managed lifetimes, in which the established context lasts until the current function returns, and affects all functions called that don't create their own contexts.
     270\lstinputlisting[language=CFA, firstline=20, lastline=34]{sharectx.run.cfa}
    92271In this example, the single-letter functions are called in alphabetic order.  The functions @a@ and @d@ share string character ranges within themselves, but not with each other.  The functions @b@, @c@ and @e@ never share anything.
    93272
    94273[ TODO: true up with ``is thread local'' (implement that and expand this discussion to give a concurrent example, or adjust this wording) ]
    95274
    96 When the string library is running with sharing disabled, it runs without implicit thread-safety challenges (which same as the STL) and with performance goals similar to the STL's.  This thread-safety quality means concurrent users of one string object must still bring their own mutual exlusion, but the string libary will not add any cross thread uses that were not apparent in the user's code.
     275When the string library is running with sharing disabled, it runs without implicit thread-safety challenges (which same as the STL) and with performance goals similar to the STL's.  This thread-safety quality means concurrent users of one string object must still bring their own mutual exclusion, but the string library will not add any cross thread uses that were not apparent in the user's code.
    97276
    98277Running with sharing disabled can be thought of as STL-emulation mode.
     
    107286
    108287
    109 \subsection{Performance assessment}
    110 
    111 I assessed the CFA string library's speed and memory usage.  I present these results ineven quivalent cases, due to either micro-optimizations foregone, or fundamental costs of the added functionality.  They also show the benefits and tradeoffs, as >100\% effects, of switching to CFA, with the tradeoff points quantified.  The final test shows the overall win of the CFA text-sharing mechanism.  It exercises several operations together, showing CFA enabling clean user code to achieve performance that STL requires less-clean user code to achieve.
    112 
    113 To discuss: general goal of ... while STL makes you think about memory management, all the time, and if you do your performance can be great ... CFA sacrifices this advantage modestly in exchange for big wins when you're not thinking about memory mamangement.  [Does this position cover all of it?]
     288\section{Performance assessment}
     289\label{s:PerformanceAssessment}
     290
     291I assessed the \CFA string library's speed and memory usage.  I present these results in even equivalent cases, due to either micro-optimizations foregone, or fundamental costs of the added functionality.  They also show the benefits and tradeoffs, as >100\% effects, of switching to \CFA, with the tradeoff points quantified.  The final test shows the overall win of the \CFA text-sharing mechanism.  It exercises several operations together, showing \CFA enabling clean user code to achieve performance that STL requires less-clean user code to achieve.
     292
     293To discuss: general goal of ... while STL makes you think about memory management, all the time, and if you do your performance can be great ... \CFA sacrifices this advantage modestly in exchange for big wins when you're not thinking about memory management.  [Does this position cover all of it?]
    114294
    115295To discuss: revisit HL v LL APIs
    116296
    117 To discuss: revisit nosharing as STL emulation modes
     297To discuss: revisit no-sharing as STL emulation modes
    118298
    119299These tests use randomly generated text fragments of varying lengths.  A collection of such fragments is a \emph{corpus}.  The mean length of a fragment from corpus is a typical explanatory variable.  Such a length is used in one of three modes:
     
    121301    \item [Fixed-size] means all string fragments are of the stated size
    122302    \item [Varying from 1] means string lengths are drawn from a geometric distribution with the stated mean, and all lengths occur
    123     \item [Varying from 16] means string lengths are drawn from a geometric distribution with the stated mean, but only lengths 16 and obove occur; thus, the stated mean will be above 16.
     303    \item [Varying from 16] means string lengths are drawn from a geometric distribution with the stated mean, but only lengths 16 and above occur; thus, the stated mean will be above 16.
    124304\end{description}
    125 The geometric distribution implies that lengths much longer than the mean occur frequently.  The special treatment of length 16 deals with comparison to STL, given that STL has short-string optimization (see [todo: write and cross-ref future-work SSO]), currently not implmented in \CFA.  When success notwithstanding SSO is illustrated, a fixed-size or from-16 distribution ensures that extra-optimized cases are not part of the mix on the STL side.  In all experiments that use a corpus, its text is generated and loaded into the SUT before the timed phase begins.
     305The geometric distribution implies that lengths much longer than the mean occur frequently.  The special treatment of length 16 deals with comparison to STL, given that STL has short-string optimization (see [TODO: write and cross-ref future-work SSO]), currently not implemented in \CFA.  When success notwithstanding SSO is illustrated, a fixed-size or from-16 distribution ensures that extra-optimized cases are not part of the mix on the STL side.  In all experiments that use a corpus, its text is generated and loaded into the SUT before the timed phase begins.
    126306
    127307To discuss: vocabulary for reused case variables
     
    136316\subsubsection{Test: Append}
    137317
    138 This test measures the speed of appending fragments of text onto a growing string.  Its subcases include both CFA being similar to STL, and their designs offering a tradeoff.
    139 
    140 One experimental variable is the user's operation being @a = a + b@ vs. @a += b@.  While experienced programmers expect the latter to be ``what you obviously should do,'' controling the penatly of the former both helps the API be accessible to beginners and also helps offer confidence that when a user tries to compose operations, the forms that are most natural to the user's composition are viable.
    141 
    142 Another experimental variable is whether the user's logical allocation is fresh vs reused.  Here, \emph{reusing a logical allocation}, means that the prgram variable, into which the user is concatenating, previously held a long string:\\
     318This test measures the speed of appending fragments of text onto a growing string.  Its subcases include both \CFA being similar to STL, and their designs offering a tradeoff.
     319
     320One experimental variable is the user's operation being @a = a + b@ vs. @a += b@.  While experienced programmers expect the latter to be ``what you obviously should do,'' controlling the penalty of the former both helps the API be accessible to beginners and also helps offer confidence that when a user tries to compose operations, the forms that are most natural to the user's composition are viable.
     321
     322Another experimental variable is whether the user's logical allocation is fresh vs reused.  Here, \emph{reusing a logical allocation}, means that the program variable, into which the user is concatenating, previously held a long string:\\
    143323\begin{tabular}{ll}
    144324    Logical allocation fresh                   & Logical allocation reused                  \\
     
    150330    @ } @                                      & @ } @
    151331\end{tabular}\\
    152 These benchmark drivers have an outer loop for ``until a sample-worthy amount of execution has happened'' and an inner loop for ``build up the desired-length string.''  It is sensible to doubt that a user should have to care about this difference, yet the STL performs differently in these cases.  Concretly, both cases incur the cost of copying characters into the target string, but only the allocation-fresh case incurs a further reallocation cost, which is generally paid at points of doubling the length.  For the STL, this cost includes obtaining a fresh buffer from the memory allocator and copying older characters into the new buffer, while CFA-sharing hides such a cost entirely.  The reuse-vs-fresh distinction is only relevant in the currrent \emph{append} tests.
    153 
    154 The \emph{append} tests use the varying-from-1 corpus construction; that is they do not assume away the STL's advantage from small-string opitimization.
    155 
    156 To discuss: any other case variables intruduced in the performance intro
     332These benchmark drivers have an outer loop for ``until a sample-worthy amount of execution has happened'' and an inner loop for ``build up the desired-length string.''  It is sensible to doubt that a user should have to care about this difference, yet the STL performs differently in these cases.  Concretely, both cases incur the cost of copying characters into the target string, but only the allocation-fresh case incurs a further reallocation cost, which is generally paid at points of doubling the length.  For the STL, this cost includes obtaining a fresh buffer from the memory allocator and copying older characters into the new buffer, while \CFA-sharing hides such a cost entirely.  The reuse-vs-fresh distinction is only relevant in the current \emph{append} tests.
     333
     334The \emph{append} tests use the varying-from-1 corpus construction; that is they do not assume away the STL's advantage from small-string optimization.
     335
     336To discuss: any other case variables introduced in the performance intro
    157337
    158338\begin{figure}
     
    162342\end{figure}
    163343
    164 Figure \ref{fig:string-graph-peq-cppemu} shows this behaviour, by the STL and by \CFA in STL emulation mode.  \CFA reproduces STL's performance, up to a 15\% penalty averaged over the cases shown, diminishing with larger strings, and 50\% in the worst case.  This penatly characterizes the amount of implementation fine tuning done with STL and not done with \CFA in present state.  The larger inherent penalty, for a user mismanaging reuse, is 40\% averaged over the cases shown, is minimally 24\%, shows up consistently between the STL and \CFA implementations, and increases with larger strings.
     344Figure \ref{fig:string-graph-peq-cppemu} shows this behaviour, by the STL and by \CFA in STL emulation mode.  \CFA reproduces STL's performance, up to a 15\% penalty averaged over the cases shown, diminishing with larger strings, and 50\% in the worst case.  This penalty characterizes the amount of implementation fine tuning done with STL and not done with \CFA in present state.  The larger inherent penalty, for a user mismanaging reuse, is 40\% averaged over the cases shown, is minimally 24\%, shows up consistently between the STL and \CFA implementations, and increases with larger strings.
    165345
    166346\begin{figure}
     
    170350\end{figure}
    171351
    172 In sharing mode, \CFA makes the fresh/reuse difference disappear, as shown in Figure \ref{fig:string-graph-peq-sharing}.  At append lengths 5 and above, CFA not only splits the two baseline STL cases, but its slowdown of 16\% over (STL with user-managed reuse) is close to the \CFA-v-STL implementation difference seen with \CFA in STL-emulation mode.
     352In sharing mode, \CFA makes the fresh/reuse difference disappear, as shown in Figure \ref{fig:string-graph-peq-sharing}.  At append lengths 5 and above, \CFA not only splits the two baseline STL cases, but its slowdown of 16\% over (STL with user-managed reuse) is close to the \CFA-v-STL implementation difference seen with \CFA in STL-emulation mode.
    173353
    174354\begin{figure}
     
    178358\end{figure}
    179359
    180 When the user takes a further step beyond the STL's optimal zone, by running @x = x + y@, as in Figure \ref{fig:string-graph-pta-sharing}, the STL's penalty is above $15 \times$ while CFA's (with sharing) is under $2 \times$, averaged across the cases shown here.  Moreover, the STL's gap increases with string size, while \CFA's converges.
     360When the user takes a further step beyond the STL's optimal zone, by running @x = x + y@, as in Figure \ref{fig:string-graph-pta-sharing}, the STL's penalty is above $15 \times$ while \CFA's (with sharing) is under $2 \times$, averaged across the cases shown here.  Moreover, the STL's gap increases with string size, while \CFA's converges.
    181361
    182362\subsubsection{Test: Pass argument}
     
    184364To have introduced:  STL string library forces users to think about memory management when communicating values across a function call
    185365
    186 STL charges a prohibitive penalty for passing a string by value.  With implicit sharing active, \CFA treats this operation as normal and supported.  This test illustrates a main adjantage of the \CFA sharing algorithm.  It also has a case in which STL's small-string optimization provides a successful mitigation.
     366STL charges a prohibitive penalty for passing a string by value.  With implicit sharing active, \CFA treats this operation as normal and supported.  This test illustrates a main advantage of the \CFA sharing algorithm.  It also has a case in which STL's small-string optimization provides a successful mitigation.
    187367
    188368\begin{figure}
     
    201381This test directly compares the allocation schemes of the \CFA string with sharing, compared with the STL string.  It treats the \CFA scheme as a form of garbage collection, and the STL scheme as an application of malloc-free.  The test shows that \CFA enables faster speed at a cost in memory usage.
    202382
    203 A garbage collector, afforded the freedom of managed memory, often runs faster than malloc-free (in an ammortized analysis, even though it must occasionally stop to collect) because it is able to use its collection time to move objects.  (In the case of the mini-allocator powering the \CFA string library, objects are runs of text.)  Moving objects lets fresh allocations consume from a large contiguous store of available memory; the ``bump pointer'' book-keeping for such a scheme is very light.  A malloc-free implementation without the freedom to move objects must, in the general case, allocate in the spaces between existing objects; doing so entails the heavier book-keeping to navigate and maintain a linked structure.
     383A garbage collector, afforded the freedom of managed memory, often runs faster than malloc-free (in an amortized analysis, even though it must occasionally stop to collect) because it is able to use its collection time to move objects.  (In the case of the mini-allocator powering the \CFA string library, objects are runs of text.)  Moving objects lets fresh allocations consume from a large contiguous store of available memory; the ``bump pointer'' book-keeping for such a scheme is very light.  A malloc-free implementation without the freedom to move objects must, in the general case, allocate in the spaces between existing objects; doing so entails the heavier book-keeping to navigate and maintain a linked structure.
    204384
    205385A garbage collector keeps allocations around for longer than the using program can reach them.  By contrast, a program using malloc-free (correctly) releases allocations exactly when they are no longer reachable.  Therefore, the same harness will use more memory while running under garbage collection.  A garbage collector can minimize the memory overhead by searching for these dead allocations aggressively, that is, by collecting more often.  Tuned in this way, it spends a lot of time collecting, easily so much as to overwhelm its speed advantage from bump-pointer allocation.  If it is tuned to collect rarely, then it leaves a lot of garbage allocated (waiting to be collected) but gains the advantage of little time spent doing collection.
     
    215395\begin{figure}
    216396    \includegraphics[width=\textwidth]{string-graph-allocn.png}
    217     \caption{Space and time performance, under varying fraction-live targets, for the five string lengths shown, at (emph{Fixed-size} corpus construction.  [MISSING] The identified clusters are for the default fraction-live target, which is 30\%.  MISSING: STL results, typically just below the 0.5--0.9 CFA segment.  All runs keep an average of 836 strings live, and the median string lifetime is ?? allocations.}
     397    \caption{Space and time performance, under varying fraction-live targets, for the five string lengths shown, at (\emph{Fixed-size} corpus construction.  [MISSING] The identified clusters are for the default fraction-live target, which is 30\%.  MISSING: STL results, typically just below the 0.5--0.9 \CFA segment.  All runs keep an average of 836 strings live, and the median string lifetime is ?? allocations.}
    218398    \label{fig:string-graph-allocn}
    219399\end{figure}
    220400
    221 Figure \ref{fig:string-graph-allocn} shows the results of this experiemnt.  At all string sizes, varying the liveness threshold gives offers speed-for-space tradeoffs relative to STL.  At the default liveness threshold, all measured string sizes see a ??\%--??\% speedup for a ??\%--??\% increase in memory footprint.
     401Figure \ref{fig:string-graph-allocn} shows the results of this experiment.  At all string sizes, varying the liveness threshold gives offers speed-for-space tradeoffs relative to STL.  At the default liveness threshold, all measured string sizes see a ??\%--??\% speedup for a ??\%--??\% increase in memory footprint.
    222402
    223403
     
    225405\subsubsection{Test: Normalize}
    226406
    227 This test is more applied than the earlier ones.  It combines the effects of several operations.  It also demonstrates a case of the CFA API allowing user code to perform well, while being written without overt memory management, while achieving similar performance in STL requires adding memory-management complexity.
     407This test is more applied than the earlier ones.  It combines the effects of several operations.  It also demonstrates a case of the \CFA API allowing user code to perform well, while being written without overt memory management, while achieving similar performance in STL requires adding memory-management complexity.
    228408
    229409To motivate: edits being rare
  • doc/theses/mike_brooks_MMath/uw-ethesis.bib

    rb006c51e r10a9479d  
    124124}
    125125
    126 
    127126@misc{Mendio24,
    128127    contributer = {pabuhr@plg},
     
    132131    howpublished= {\url{https://www.mend.io/most-secure-programming-languages}},
    133132}
     133
     134@misc{RVO20,
     135    contributer = {pabuhr@plg},
     136    title       = {Return value optimization ({RVO})},
     137    author      = {Special Interest Group on {C++}},
     138    year        = 2020,
     139    month       = jun,
     140    howpublished= {\url{https://sigcpp.github.io/2020/06/08/return-value-optimization}},
     141}
  • doc/theses/mike_brooks_MMath/uw-ethesis.tex

    rb006c51e r10a9479d  
    102102\input{common}
    103103%\usepackage{common}
     104
    104105\CFAStyle                                               % CFA code-style
    105106\lstset{language=cfa,belowskip=-1pt} % set default language to CFA
     
    108109\lstnewenvironment{java}[1][]{\lstset{language=java,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    109110\lstset{inputpath={programs}}
     111\lstset{xleftmargin=1\parindentlnth}
    110112
    111113\newcommand{\uCpp}{$\mu$\CC}
Note: See TracChangeset for help on using the changeset viewer.