Changeset 579427b for doc/theses/mike_brooks_MMath/array.tex
- Timestamp:
- May 7, 2025, 9:48:24 PM (5 months ago)
- Branches:
- master
- Children:
- ed0a7e5
- Parents:
- 2c065ed
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/mike_brooks_MMath/array.tex
r2c065ed r579427b 17 17 though using a new style of generic parameter. 18 18 \begin{cfa} 19 @array( float, 99 )@ x; $\C[2. 75in]{// x contains 99 floats}$20 \end{cfa} 21 Here, the arguments to the @array@ type are @float@ (element type) and @99@ ( length).22 When this type is used as a function parameter, the type-system requires th at a call'sargument is a perfect match.19 @array( float, 99 )@ x; $\C[2.5in]{// x contains 99 floats}$ 20 \end{cfa} 21 Here, the arguments to the @array@ type are @float@ (element type) and @99@ (dimension). 22 When this type is used as a function parameter, the type-system requires the argument is a perfect match. 23 23 \begin{cfa} 24 24 void f( @array( float, 42 )@ & p ) {} $\C{// p accepts 42 floats}$ 25 25 f( x ); $\C{// statically rejected: type lengths are different, 99 != 42}$ 26 27 26 test2.cfa:3:1 error: Invalid application of existing declaration(s) in expression. 28 27 Applying untyped: Name: f ... to: Name: x 29 28 \end{cfa} 30 Here, the function @f@'s parameter @p@ is declared with length 42. 31 However, the call @f( x )@ is invalid, because @x@'s length is @99@, which does not match @42@. 32 33 A function declaration can be polymorphic over these @array@ arguments by using the \CFA @forall@ declaration prefix. 29 Function @f@'s parameter expects an array with dimension 42, but the argument dimension 99 does not match. 30 31 A function can be polymorphic over @array@ arguments using the \CFA @forall@ declaration prefix. 34 32 \begin{cfa} 35 33 forall( T, @[N]@ ) … … 38 36 } 39 37 g( x, 0 ); $\C{// T is float, N is 99, dynamic subscript check succeeds}$ 40 g( x, 1000 ); $\C{// T is float, N is 99, dynamic subscript check fails}\CRT$ 41 38 g( x, 1000 ); $\C{// T is float, N is 99, dynamic subscript check fails}$ 42 39 Cforall Runtime error: subscript 1000 exceeds dimension range [0,99) $for$ array 0x555555558020. 43 40 \end{cfa} 44 Function @g@ takes an arbitrary type parameter @T@ and a \emph{dimension parameter} @N@. 45 A dimension parameter represents a to-be-determined count of elements, managed by the type system. 46 The 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@. 47 Inferring values for @T@ and @N@ is implicit. 48 Furthermore, 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@. 49 However, the call @g( x, 1000 )@ is also accepted through compile time; 50 however, this case's subscript, @x[1000]@, generates an error, because @1000@ is outside the dimension range $[0,99)$ of argument @x@. 41 Function @g@ takes an arbitrary type parameter @T@ and an unsigned integer \emph{dimension} @N@. 42 The dimension represents a to-be-determined number of elements, managed by the type system, where 0 represents an empty array. 43 The type system implicitly infers @float@ for @T@ and @99@ for @N@. 44 Furthermore, the runtime subscript @x[0]@ (parameter @i@ being @0@) in @g@ is valid because 0 is in the dimension range $[0,99)$ for argument @x@. 45 The call @g( x, 1000 )@ is also accepted at compile time. 46 However, the subscript, @x[1000]@, generates a runtime error, because @1000@ is outside the dimension range $[0,99)$ of argument @x@. 51 47 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. 52 48 The syntactic form is chosen to parallel other @forall@ forms: 53 49 \begin{cfa} 54 forall( @[N]@ ) ... $\C [1.5in]{// dimension}$55 forall( T ) ... $\C{// value datatype (formerly, "otype")}$56 forall( T & ) ... $\C{// opaque datatype (formerly, "dtype")}\CRT$50 forall( @[N]@ ) ... $\C{// dimension}$ 51 forall( T ) ... $\C{// value datatype}$ 52 forall( T & ) ... $\C{// opaque datatype}$ 57 53 \end{cfa} 58 54 % The notation @array(thing, N)@ is a single-dimensional case, giving a generic type instance. … … 63 59 \begin{cfa} 64 60 forall( [N] ) 65 void declDemo( ... ) { 66 float x1[N]; $\C{// built-in type ("C array")}$ 67 array(float, N) x2; $\C{// type from library}$ 68 } 69 \end{cfa} 70 Both of the locally-declared array variables, @x1@ and @x2@, have 42 elements, each element being a @float@. 71 The two variables have identical size and layout; they both encapsulate 42-float stack allocations, with no additional ``bookkeeping'' allocations or headers. 61 void f( ... ) { 62 float x1[@N@]; $\C{// C array, no subscript checking}$ 63 array(float, N) x2; $\C{// \CFA array, subscript checking}\CRT$ 64 } 65 \end{cfa} 66 Both of the stack declared array variables, @x1@ and @x2@, have 42 elements, each element being a @float@. 67 The two variables have identical size and layout, with no additional ``bookkeeping'' allocations or headers. 68 The C array, @x1@, has no subscript checking, while \CFA array, @x2@, does. 72 69 Providing 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. 73 In 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 75 Admittedly, the @array@ library type for @x2@ is syntactically different from its C counterpart. 76 A future goal (TODO xref) is to provide the new @array@ features with syntax approaching C's (declaration style of @x1@). 70 In all following discussion, ``C array'' means types like @x1@ and ``\CFA array'' means types like @x2@. 71 72 A future goal is to provide the new @array@ features with syntax approaching C's (declaration style of @x1@). 77 73 Then, the library @array@ type could be removed, giving \CFA a largely uniform array type. 78 At present, the C-syntax @array@ is only partially supported, so the generic @array@ is used exclusively in the thesis; 79 feature support and C compatibility are revisited in Section ? TODO. 74 At present, the C-syntax @array@ is only partially supported, so the generic @array@ is used exclusively in the thesis. 80 75 81 76 My contributions in this chapter are: 82 \begin{enumerate} 77 \begin{enumerate}[leftmargin=*] 83 78 \item A type system enhancement that lets polymorphic functions and generic types be parameterized by a numeric value: @forall( [N] )@. 84 \item Provide a length-checked array-type in the \CFA standard library, where the array's length is statically managed and dynamically valued.79 \item Provide a dimension/subscript-checked array-type in the \CFA standard library, where the array's length is statically managed and dynamically valued. 85 80 \item Provide argument/parameter passing safety for arrays and subscript safety. 86 \item TODO: general parking...87 81 \item Identify the interesting specific abilities available by the new @array@ type. 88 82 \item Where there is a gap concerning this feature's readiness for prime-time, identification of specific workable improvements that are likely to close the gap. … … 90 84 91 85 86 \begin{comment} 92 87 \section{Dependent Typing} 93 88 94 General dependent typing allows the type system to encode arbitrary predicates (\eg behavioural specifications for functions), 95 which is an anti-goal for my work. 89 General dependent typing allows a type system to encode arbitrary predicates, \eg behavioural specifications for functions, which is an anti-goal for my work. 96 90 Firstly, this application is strongly associated with pure functional languages, 97 91 where a characterization of the return value (giving it a precise type, generally dependent upon the parameters) … … 101 95 Secondly, TODO: bash Rust. 102 96 TODO: cite the crap out of these claims. 97 \end{comment} 103 98 104 99 105 100 \section{Features Added} 106 101 107 This section shows more about using the \CFA array and dimension parameters, demonstrating theirsyntax and semantics by way of motivating examples.102 This section shows more about using the \CFA array and dimension parameters, demonstrating syntax and semantics by way of motivating examples. 108 103 As stated, the core capability of the new array is tracking all dimensions within the type system, where dynamic dimensions are represented using type variables. 109 104 110 105 By declaring type variables at the front of object declarations, an array dimension is lexically referenceable where it is needed. 111 For example, a declaration can share one length, @N@, among a pair of parameters and the return, 112 meaning that it requires both input arrays to be of the same length, and guarantees that the result is of that length as well. 106 For example, a declaration can share one length, @N@, among a pair of parameters and return type, meaning the input arrays and return array are the same length. 113 107 \lstinput{10-17}{hello-array.cfa} 114 108 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. 115 The dynamic allocation of the @ret@ array , bythe library @alloc@ function,109 The dynamic allocation of the @ret@ array uses the library @alloc@ function, 116 110 \begin{cfa} 117 111 forall( T & | sized(T) ) … … 120 114 } 121 115 \end{cfa} 122 uses the parameterized dimension information implicitly within its @sizeof@ determination, and casts the return type.123 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 which captures the parameterized dimension information implicitly within its @sizeof@ determination, and casts the return type. 117 Note, @alloc@ only sees the whole type for its @T@, @array(bool, N)@, where this type's size is a computation based on @N@. 124 118 This example illustrates how the new @array@ type plugs into existing \CFA behaviour by implementing necessary \emph{sized} assertions needed by other types. 125 119 (\emph{sized} implies a concrete \vs abstract type with a runtime-available size, exposed as @sizeof@.) … … 129 123 \lstinput{30-43}{hello-array.cfa} 130 124 \lstinput{45-48}{hello-array.cfa} 131 \caption{\lstinline{f} Harness}132 \label{f:f Harness}125 \caption{\lstinline{f} Example} 126 \label{f:fExample} 133 127 \end{figure} 134 128 135 \VRef[Figure]{f:f Harness} shows a harness that usesfunction @f@, illustrating how dynamic values are fed into the @array@ type.129 \VRef[Figure]{f:fExample} shows an example using function @f@, illustrating how dynamic values are fed into the @array@ type. 136 130 Here, the dimension of arrays @x@, @y@, and @result@ is specified from a command-line value, @dim@, and these arrays are allocated on the stack. 137 131 Then the @x@ array is initialized with decreasing values, and the @y@ array with amounts offset by constant @0.005@, giving relative differences within tolerance initially and diverging for later values. … … 144 138 145 139 In summary: 146 \begin{itemize} 140 \begin{itemize}[leftmargin=*] 147 141 \item 148 142 @[N]@ within a @forall@ declares the type variable @N@ to be a managed length. 149 143 \item 150 @N@ can be used an expression of type @size_t@ within the declaredfunction body.144 @N@ can be used in an expression with type @size_t@ within the function body. 151 145 \item 152 146 The value of an @N@-expression is the acquired length, derived from the usage site, \ie generic declaration or function call. … … 158 152 \begin{enumerate}[leftmargin=*] 159 153 \item 160 The \CC template @N@ can only be compile-time value, while the \CFA @N@ may be a runtime value. 161 % agreed, though already said 154 The \CC template @N@ can only be a compile-time value, while the \CFA @N@ may be a runtime value. 162 155 \item 163 156 \CC does not allow a template function to be nested, while \CFA lets its polymorphic functions to be nested. 164 % why is this important? 165 \item 157 Hence, \CC precludes a simple form of information hiding. 158 \item 159 \label{p:DimensionPassing} 166 160 The \CC template @N@ must be passed explicitly at the call, unless @N@ has a default value, even when \CC can deduct the type of @T@. 167 161 The \CFA @N@ is part of the array type and passed implicitly at the call. … … 169 163 % mycode/arrr/thesis-examples/check-peter/cs-cpp.cpp, v2 170 164 \item 171 \CC cannot have an array of references, but can have an array of pointers.165 \CC cannot have an array of references, but can have an array of @const@ pointers. 172 166 \CC has a (mistaken) belief that references are not objects, but pointers are objects. 173 167 In the \CC example, the arrays fall back on C arrays, which have a duality with references with respect to automatic dereferencing. … … 178 172 % https://stackoverflow.com/questions/922360/why-cant-i-make-a-vector-of-references 179 173 \item 174 \label{p:ArrayCopy} 180 175 C/\CC arrays cannot be copied, while \CFA arrays can be copied, making them a first-class object (although array copy is often avoided for efficiency). 181 176 % fixed by comparing to std::array 182 177 % mycode/arrr/thesis-examples/check-peter/cs-cpp.cpp, v10 183 178 \end{enumerate} 184 T ODO: settle Mike's concerns with this comparison (perhaps, remove)179 The \CC template @array@ type mitigates points \VRef[]{p:DimensionPassing} and \VRef[]{p:ArrayCopy}, but it is also trying to accomplish a similar mechanism to \CFA @array@. 185 180 186 181 \begin{figure} … … 226 221 Just as the first example in \VRef[Section]{s:ArrayIntro} shows a compile-time rejection of a length mismatch, 227 222 so are length mismatches stopped when they involve dimension parameters. 228 While \VRef[Figure]{f:f Harness} shows successfully calling a function @f@ expecting two arrays of the same length,223 While \VRef[Figure]{f:fExample} shows successfully calling a function @f@ expecting two arrays of the same length, 229 224 \begin{cfa} 230 225 array( bool, N ) & f( array( float, N ) &, array( float, N ) & ); … … 246 241 The same argument safety and the associated implicit communication of array length occurs. 247 242 Preexisting \CFA allowed aggregate types to be generalized with type parameters, enabling parameterizing of element types. 248 Now, \CFA also allows parameterizing them by length. 249 Doing so gives a refinement of C's ``flexible array member'' pattern[TODO: cite ARM 6.7.2.1 pp18]\cite{arr:gnu-flex-mbr}. 250 While a C flexible array member can only occur at the end of the enclosing structure, 251 \CFA allows length-parameterized array members to be nested at arbitrary locations. 252 This flexibility, in turn, allows for multiple array members. 243 This has been extended to allow parameterizing by dimension. 244 Doing so gives a refinement of C's ``flexible array member''~\cite[\S~6.7.2.1.18]{C11}. 245 \begin{cfa} 246 struct S { 247 ... 248 double d []; // incomplete array type => flexible array member 249 } * s = malloc( sizeof( struct S ) + sizeof( double [10] ) ); 250 \end{cfa} 251 which creates a VLA of size 10 @double@s at the end of the structure. 252 A C flexible array member can only occur at the end of a structure; 253 \CFA allows length-parameterized array members to be nested at arbitrary locations, with intervening member declarations. 253 254 \lstinput{10-15}{hello-accordion.cfa} 254 255 The structure has course- and student-level metatdata (their respective field names) and a position-based preferences' matrix. 255 256 Its 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 257 \VRef[Figure]{f:check Harness} shows a program main using @School@ and results with different array sizes.258 \VRef[Figure]{f:checkExample} shows a program main using @School@ and results with different array sizes. 258 259 The @school@ variable holds many students' course-preference forms. 259 260 It is on the stack and its initialization does not use any casting or size arithmetic. … … 285 286 \end{cquote} 286 287 287 \caption{\lstinline{School} harness, input and output}288 \label{f:check Harness}288 \caption{\lstinline{School} Example, Input and Output} 289 \label{f:checkExample} 289 290 \end{figure} 290 291 291 292 When a function operates on a @School@ structure, the type system handles its memory layout transparently. 292 293 \lstinput{30-37}{hello-accordion.cfa} 293 In the example, this @getPref@ function answers, for the student at position @is@, what is the position of its@pref@\textsuperscript{th}-favoured class?294 In the example, function @getPref@ returns, for the student at position @is@, what is the position of their @pref@\textsuperscript{th}-favoured class? 294 295 295 296 … … 324 325 325 326 The repurposed heavy equipment is 326 \begin{itemize} 327 \begin{itemize}[leftmargin=*] 327 328 \item 328 329 Resolver provided values for a used declaration's type-system variables, … … 348 349 int main() { 349 350 thing( @10@ ) x; f( x ); $\C{// prints 10, [4]}$ 350 thing( 100 ) y; f( y ); $\C{// prints 100}$ 351 return 0; 351 thing( @100@ ) y; f( y ); $\C{// prints 100}$ 352 352 } 353 353 \end{cfa} 354 354 This example has: 355 \begin{enumerate} 355 \begin{enumerate}[leftmargin=*] 356 356 \item 357 357 The symbol @N@ being declared as a type variable (a variable of the type system). … … 369 369 Because the box pass handles a type's size as its main datum, the encoding is chosen to use it. 370 370 The production and recovery are then straightforward. 371 \begin{itemize} 371 \begin{itemize}[leftmargin=*] 372 372 \item 373 373 The value $n$ is encoded as a type whose size is $n$. 374 374 \item 375 Given a dimension expression $e$, produce type @char[@$e$@]@ to represent it.375 Given a dimension expression $e$, produce an internal type @char[@$e$@]@ to represent it. 376 376 If $e$ evaluates to $n$ then the encoded type has size $n$. 377 377 \item … … 389 389 } 390 390 int 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; 391 thing( @char[10]@ ) x; f( x ); $\C{// prints 10, [4]}$ 392 thing( @char[100]@ ) y; f( y ); $\C{// prints 100}$ 394 393 } 395 394 \end{cfa} 396 395 Observe: 397 \begin{enumerate} 396 \begin{enumerate}[leftmargin=*] 398 397 \item 399 398 @N@ is now declared to be a type. 400 It is declared to be \emph{sized} (by the @*@), meaning that the box pass shall do its @sizeof(N)@ --@__sizeof_N@ extra parameter and expression translation.399 It is declared to be \emph{sized} (by the @*@), meaning that the box pass shall do its @sizeof(N)@$\rightarrow$@__sizeof_N@ extra parameter and expression translation. 401 400 \item 402 401 @thing(N)@ is a type; the argument to the generic @thing@ is a type (type variable). … … 404 403 The @sout...@ expression (being an application of the @?|?@ operator) has a second argument that is an ordinary expression. 405 404 \item 406 The type of variable @x@ is another @thing(-)@ type; the argument to the generic @thing@ is a type (array type of bytes, @char @).405 The type of variable @x@ is another @thing(-)@ type; the argument to the generic @thing@ is a type (array type of bytes, @char[@$e$@]@). 407 406 \end{enumerate} 408 407 … … 415 414 struct __conc_thing_10 {} x; f( @10@, &x ); $\C{// prints 10, [4]}$ 416 415 struct __conc_thing_100 {} y; f( @100@, &y ); $\C{// prints 100}$ 417 return 0;418 416 } 419 417 \end{cfa} 420 418 Observe: 421 \begin{enumerate} 419 \begin{enumerate}[leftmargin=*] 422 420 \item 423 421 The type parameter @N@ is gone. … … 427 425 The @sout...@ expression (being an application of the @?|?@ operator) has a regular variable (parameter) usage for its second argument. 428 426 \item 429 Information about the particular @thing@ instantiation (value 10) has moved, from the type, to a regular function-call argument.427 Information about the particular @thing@ instantiation (value 10) is moved, from the type, to a regular function-call argument. 430 428 \end{enumerate} 431 429 At the end of the desugaring and downstream processing, the original C idiom of ``pass both a length parameter and a pointer'' has been reconstructed. … … 433 431 The compiler's action produces the more complex form, which if handwritten, would be error-prone. 434 432 435 Back at the compiler front end, the parsing changes AST schema extensions and validation rules for enabling the sugared user input.436 \begin{itemize} 433 At the compiler front end, the parsing changes AST schema extensions and validation rules for enabling the sugared user input. 434 \begin{itemize}[leftmargin=*] 437 435 \item 438 436 Recognize the form @[N]@ as a type-variable declaration within a @forall@. … … 440 438 Have the new brand of type-variable, \emph{Dimension}, in the AST form of a type-variable, to represent one parsed from @[-]@. 441 439 \item 442 Allow a type variable to occur in an expression. Validate (after parsing) that only dimension-branded type 440 Allow a type variable to occur in an expression. Validate (after parsing) that only dimension-branded type-variables are used here. 443 441 \item 444 442 Allow an expression to occur in type-argument position. Brand the resulting type argument as a dimension. … … 457 455 \label{s:ArrayTypingC} 458 456 459 Essential in giving a guarantee of accurate length is the compiler's ability 460 to reject a program that presumes to mishandle length. 461 By contrast, most discussion so far dealt with communicating length, 462 from one party who knows it, to another who is willing to work with any given length. 463 For scenarios where the concern is a mishandled length, 464 the interaction is between two parties who both claim to know something about it. 465 Such a scenario occurs in this pure C fragment, which today's C compilers accept: 466 \begin{cfa} 467 int n = @42@; 468 float x[n]; 469 float (*xp)[@999@] = &x; 457 Essential in giving a guarantee of accurate length is the compiler's ability to reject a program that presumes to mishandle length. 458 By contrast, most discussion so far deals with communicating length, from one party who knows it, to another willing to work with any given length. 459 For scenarios where the concern is a mishandled length, the interaction is between two parties who both claim to know something about it. 460 461 C and \CFA can check when working with two static values. 462 \begin{cfa} 463 enum { n = 42 }; 464 float x[@n@]; // or just 42 465 float (*xp1)[@42@] = &x; // accept 466 float (*xp2)[@999@] = &x; // reject 467 warning: initialization of 'float (*)[999]' from incompatible pointer type 'float (*)[42]' 468 \end{cfa} 469 When a variable is involved, C and \CFA take two different approaches. 470 Today's C compilers accept the following without warning. 471 \begin{cfa} 472 static const int n = 42; 473 float x[@n@]; 474 float (* xp)[@999@] = &x; $\C{// should be static rejection here}$ 470 475 (*xp)[@500@]; $\C{// in "bound"?}$ 471 476 \end{cfa} 472 477 Here, the array @x@ has length 42, while a pointer to it (@xp@) claims length 999. 473 So, while the subscript of @xp@ at position 500 is out of bound ofits referent @x@,478 So, while the subscript of @xp@ at position 500 is out of bound with its referent @x@, 474 479 the access appears in-bound of the type information available on @xp@. 475 Truly, length is being mishandled in the previous step, 476 where the type-carried length information on @x@ is not compatible with that of @xp@. 477 478 The \CFA new-array rejects the analogous case: 479 \begin{cfa} 480 int n = @42@; 481 array(float, n) x; 482 array(float, 999) * xp = x; $\C{// static rejection here}$ 483 (*xp)[@500@]; $\C{// runtime check vs len 999}$ 484 \end{cfa} 485 The way the \CFA array is implemented, the type analysis of this case reduces to a case similar to the earlier C version. 480 In fact, length is being mishandled in the previous step, where the type-carried length information on @x@ is not compatible with that of @xp@. 481 482 In \CFA, I choose to reject this C example at the point where the type-carried length information on @x@ is not compatible with that of @xp@, and correspondingly, its array counterpart at the same location: 483 \begin{cfa} 484 static const int n = 42; 485 array( float, @n@ ) x; 486 array( float, @999@ ) * xp = &x; $\C{// static rejection here}$ 487 (*xp)[@500@]; $\C{// runtime check passes}$ 488 \end{cfa} 489 The way the \CFA array is implemented, the type analysis for this case reduces to a case similar to the earlier C version. 486 490 The \CFA compiler's compatibility analysis proceeds as: 487 491 \begin{itemize}[parsep=0pt] 488 492 \item 489 Is @array(float, 999)@ type-compatible with @array(float, n)@? 490 \item 491 Is @arrayX(float, char[999])@ type-compatible with @arrayX(float, char[n])@?\footnote{ 492 Here, \lstinline{arrayX} represents the type that results 493 from desugaring the \lstinline{array} type 494 into a type whose generic parameters are all types. 495 This presentation elides the noisy fact that 496 \lstinline{array} is actually a macro for something bigger; 497 the reduction to \lstinline{char[-]} still proceeds as sketched.} 498 \item 499 Is @char[999]@ type-compatible with @char[n]@? 493 Is @array( float, 999 )@ type-compatible with @array( float, n )@? 494 \item 495 Is desugared @array( float, char[999] )@ type-compatible with desugared @array( float, char[n] )@? 496 % \footnote{ 497 % Here, \lstinline{arrayX} represents the type that results from desugaring the \lstinline{array} type into a type whose generic parameters are all types. 498 % This presentation elides the noisy fact that \lstinline{array} is actually a macro for something bigger; 499 % the reduction to \lstinline{char [-]} still proceeds as sketched.} 500 \item 501 Is internal type @char[999]@ type-compatible with internal type @char[n]@? 500 502 \end{itemize} 501 To achieve the necessary \CFA rejections meant rejecting the corresponding C case, which is not backward compatible. 502 There are two complementary mitigations for this incompatibility. 503 504 First, a simple recourse is available to a programmer who intends to proceed 505 with the statically unsound assignment. 506 This situation might arise if @n@ were known to be 999, 507 rather than 42, as in the introductory examples. 508 The programmer can add a cast in the \CFA code. 509 \begin{cfa} 510 xp = @(float (*)[999])@ &x; 511 \end{cfa} 512 This addition causes \CFA to accept, because now, the programmer has accepted blame. 513 This addition is benign in plain C, because the cast is valid, just unnecessary there. 514 Moreover, the addition can even be seen as appropriate ``eye candy,'' 515 marking where the unchecked length knowledge is used. 516 Therefore, a program being onboarded to \CFA can receive a simple upgrade, 517 to satisfy the \CFA rules (and arguably become clearer), 518 without giving up its validity to a plain C compiler. 519 520 Second, the incompatibility only affects types like pointer-to-array, 521 which are are infrequently used in C. 522 The more common C idiom for aliasing an array is to use a pointer-to-first-element type, 523 which does not participate in the \CFA array's length checking.\footnote{ 503 The answer is false because, in general, the value of @n@ is unknown at compile time, and hence, an error is raised. 504 For safety, it makes sense to reject the corresponding C case, which is a non-backwards compatible change. 505 There are two mitigations for this incompatibility. 506 507 First, a simple recourse is available in a situation where @n@ is \emph{known} to be 999 by using a cast. 508 \begin{cfa} 509 float (* xp)[999] = @(float (*)[999])@&x; 510 \end{cfa} 511 The cast means the programmer has accepted blame. 512 Moreover, the cast is ``eye candy'' marking where the unchecked length knowledge is used. 513 Therefore, a program being onboarded to \CFA requires some upgrading to satisfy the \CFA rules (and arguably become clearer), without giving up its validity to a plain C compiler. 514 Second, the incompatibility only affects types like pointer-to-array, which are infrequently used in C. 515 The more common C idiom for aliasing an array is to use a pointer-to-first-element type, which does not participate in the \CFA array's length checking.\footnote{ 524 516 Notably, the desugaring of the \lstinline{array} type avoids letting any \lstinline{-[-]} type decay, 525 517 in order to preserve the length information that powers runtime bound-checking.} 526 Therefore, the frequency of needing to upgrade legacy C code (as discussed in the first mitigation) 527 is anticipated to be low. 528 529 Because the incompatibility represents a low cost to a \CFA onboarding effort 530 (with a plausible side benefit of linting the original code for a missing annotation), 531 no special measures were added to retain the compatibility. 532 It would be possible to flag occurrences of @-[-]@ types that come from @array@ desugaring, 533 treating those with stricter \CFA rules, while treating others with classic C rules. 534 If future lessons from C project onboarding warrant it, 535 this special compatibility measure can be added. 536 537 Having allowed that both the initial C example's check 538 \begin{itemize} 539 \item 540 Is @float[999]@ type-compatible with @float[n]@? 541 \end{itemize} 542 and the second \CFA example's induced check 543 \begin{itemize} 544 \item 545 Is @char[999]@ type-compatible with @char[n]@? 546 \end{itemize} 547 shall have the same answer, (``no''), 548 discussion turns to how I got the \CFA compiler to produce this answer. 549 In its preexisting form, it produced a (buggy) approximation of the C rules. 550 To implement the new \CFA rules, I took the syntactic recursion a step further, obtaining, 551 in both cases: 552 \begin{itemize} 553 \item 554 Is @999@ compatible with @n@? 555 \end{itemize} 556 This compatibility question applies to a pair of expressions, where the earlier implementation were to types. 557 Such an expression-compatibility question is a new addition to the \CFA compiler. 558 Note, these questions only arise in the context of dimension expressions on (C) array types. 559 560 TODO: ensure these compiler implementation matters are treated under \CFA compiler background: 561 type unification, 562 cost calculation, 563 GenPoly. 564 565 The relevant technical component of the \CFA compiler is the type unification procedure within the type resolver. 566 I added rules for continuing this unification into expressions that occur within types. 567 It is still fundamentally doing \emph{type} unification 568 because it is participating in binding type variables, 569 and not participating in binding any variables that stand in for expression fragments 570 (for there is no such sort of variable in \CFA's analysis.) 571 An unfortunate fact about the \CFA compiler's preexisting implementation is that 572 type unification suffers from two forms of duplication. 573 574 The first duplication has (many of) the unification rules stated twice. 575 As a result, my additions for dimension expressions are stated twice. 576 The extra statement of the rules occurs in the @GenPoly@ module, 577 where concrete types like @array(int, 5)@\footnote{ 578 Again, the presentation is simplified 579 by leaving the \lstinline{array} macro unexpanded.} 580 are lowered into corresponding C types @struct __conc_array_1234@ (the suffix being a generated index). 581 In this case, the struct's definition contains fields that hardcode the argument values of @float@ and @5@. 582 The next time an @array(-,-)@ concrete instance is encountered, it checks if the previous @struct __conc_array_1234@ is suitable for it. 583 Yes, for another occurrence of @array(int, 5)@; 584 no, for either @array(rational(int), 5)@ or @array(int, 42)@. 585 By the last example, this phase must ``reject'' 586 the hypothesis that it should reuse the dimension-5 instance's C-lowering for a dimension-42 instance. 587 588 The second duplication has unification (proper) being invoked at two stages of expression resolution. 589 As a result, my added rule set needs to handle more cases than the preceding discussion motivates. 590 In the program 591 \begin{cfa} 592 void @f@( double ); 593 forall( T & ) void @f@( T & ); 594 void g( int n ) { 595 array( float, n + 1 ) x; 596 f(x); // overloaded 597 } 598 \end{cfa} 599 when resolving the function call, @g@, the first unification stage 600 compares the type @T@ of the parameter with @array( float, n + 1 )@, of the argument. 601 TODO: finish. 602 603 The actual rules for comparing two dimension expressions are conservative. 604 To answer, ``yes, consider this pair of expressions to be matching,'' 605 is to imply, ``all else being equal, allow an array with length calculated by $e_1$ 606 to be passed to a function expecting a length-$e_2$ array.''\footnote{ 607 TODO: Deal with directionality, that I'm doing exact-match, no ``at least as long as,'' no subtyping. 608 Should it be an earlier scoping principle? Feels like it should matter in more places than here.} 609 So, a ``yes'' answer must represent a guarantee that both expressions evaluate the 610 same result, while a ``no'' can tolerate ``they might, but we're not sure'', 611 provided that practical recourses are available 612 to let programmers express better knowledge. 613 The new rule-set in the current release is, in fact, extremely conservative. 614 I chose to keep things simple, 615 and allow future needs to drive adding additional complexity, within the new framework. 616 617 For starters, the original motivating example's rejection 618 is not based on knowledge that 619 the @xp@ length of (the literal) 999 is value-unequal to 620 the (obvious) runtime value of the variable @n@, which is the @x@ length. 621 Rather, the analysis assumes a variable's value can be anything, 622 and so there can be no guarantee that its value is 999. 623 So, a variable and a literal can never match. 624 625 Two occurrences of the same literal value are obviously a fine match. 626 For two occurrences of the same variable, more information is needed. 627 For example, this one is fine 628 \begin{cfa} 629 void f( const int n ) { 630 float x[n]; 631 float (*xp)[n] = x; // accept 632 } 633 \end{cfa} 634 while this one is not: 635 \begin{cfa} 518 Therefore, the need to upgrade legacy C code is low. 519 Finally, if this incompatibility is a problem onboarding C programs to \CFA, it is should be possible to change the C type check to a warning rather than an error, acting as a \emph{lint} of the original code for a missing type annotation. 520 521 To handle two occurrences of the same variable, more information is needed, \eg, this is fine, 522 \begin{cfa} 523 int n = 42; 524 float x[@n@]; 525 float (*xp)[@n@] = x; // accept 526 \end{cfa} 527 where @n@ remains fixed across a contiguous declaration context. 528 However, intervening dynamic statement cause failures. 529 \begin{cfa} 530 int n = 42; 531 float x[@n@]; 532 @n@ = 999; // dynamic change 533 float (*xp)[@n@] = x; // reject 534 \end{cfa} 535 However, side-effects can occur in a contiguous declaration context. 536 \begin{cquote} 537 \setlength{\tabcolsep}{20pt} 538 \begin{tabular}{@{}ll@{}} 539 \begin{cfa} 540 // compile unit 1 541 extern int @n@; 542 extern float g(); 636 543 void f() { 637 int n = 42; 638 float x[n]; 639 n = 999; 640 float (*xp)[n] = x; // reject 641 } 642 \end{cfa} 643 Furthermore, the fact that the first example sees @n@ as @const@ 644 is not actually sufficient. 645 In this example, @f@'s length expression's declaration is as @const@ as it can be, 646 yet its value still changes between the two invocations: 647 \begin{cquote} 648 \setlength{\tabcolsep}{15pt} 649 \begin{tabular}{@{}ll@{}} 650 \begin{cfa} 651 // compile unit 1 652 void g(); 653 void f( const int & const nr ) { 654 float x[nr]; 655 g(); // change n 656 @float (*xp)[nr] = x;@ // reject 544 float x[@n@] = { g() }; 545 float (*xp)[@n@] = x; // reject 657 546 } 658 547 \end{cfa} … … 660 549 \begin{cfa} 661 550 // compile unit 2 662 static int n= 42;551 int @n@ = 42; 663 552 void g() { 664 n= 99;665 } 666 667 f( n ); 553 @n@ = 99; 554 } 555 556 668 557 \end{cfa} 669 558 \end{tabular} … … 671 560 The issue here is that knowledge needed to make a correct decision is hidden by separate compilation. 672 561 Even within a translation unit, static analysis might not be able to provide all the information. 673 674 My rule set also respects a traditional C feature: In spite of the several limitations of the C rules 675 accepting cases that produce different values, there are a few mismatches that C stops. 676 C is quite precise when working with two static values. 677 \begin{cfa} 678 enum { fortytwo = 42 }; 679 float x[fortytwo]; 680 float (*xp1)[42] = &x; // accept 681 float (*xp2)[999] = &x; // reject 682 \end{cfa} 683 My \CFA rules agree with C's on these cases. 562 However, if the example uses @const@, the check is possible. 563 \begin{cquote} 564 \setlength{\tabcolsep}{20pt} 565 \begin{tabular}{@{}ll@{}} 566 \begin{cfa} 567 // compile unit 1 568 extern @const@ int n; 569 extern float g(); 570 void f() { 571 float x[n] = { g() }; 572 float (*xp)[n] = x; // reject 573 } 574 \end{cfa} 575 & 576 \begin{cfa} 577 // compile unit 2 578 @const@ int n = 42; 579 void g() { 580 @n = 99@; // allowed 581 } 582 583 584 \end{cfa} 585 \end{tabular} 586 \end{cquote} 684 587 685 588 In summary, the new rules classify expressions into three groups: 686 589 \begin{description} 687 590 \item[Statically Evaluable] 688 Expressions for which a specific value can be calculated (conservatively) 689 at compile-time. 690 A preexisting \CFA compiler module defines which literals, enumerators, and expressions qualify, 691 and evaluates them. 591 Expressions for which a specific value can be calculated (conservatively) at compile-time. 592 A preexisting \CFA compiler module defines which literals, enumerators, and expressions qualify and evaluates them. 692 593 \item[Dynamic but Stable] 693 594 The value of a variable declared as @const@, including a @const@ parameter. 694 595 \item[Potentially Unstable] 695 596 The catch-all category. Notable examples include: 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 698 any use of a reference-typed variable. 597 any function-call result, @float x[foo()]@, the particular function-call result that is a pointer dereference, @void f(const int * n)@ @{ float x[*n]; }@, and any use of a reference-typed variable. 699 598 \end{description} 700 599 Within these groups, my \CFA rules are: 701 \begin{itemize} 600 \begin{itemize}[leftmargin=*] 702 601 \item 703 602 Accept a Statically Evaluable pair, if both expressions have the same value. … … 710 609 \end{itemize} 711 610 The traditional C rules are: 712 \begin{itemize} 611 \begin{itemize}[leftmargin=*] 713 612 \item 714 613 Reject a Statically Evaluable pair, if the expressions have two different values. … … 716 615 Otherwise, accept. 717 616 \end{itemize} 617 \VRef[Figure]{f:DimexprRuleCompare} gives a case-by-case comparison of the consequences of these rule sets. 618 It demonstrates that the \CFA false alarms occur in the same cases as C treats unsafe. 619 It also shows that C-incompatibilities only occur in cases that C treats unsafe. 718 620 719 621 \begin{figure} … … 746 648 where \lstinline{expr1} and \lstinline{expr2} are meta-variables varying according to the row's Case. 747 649 Each row's claim applies to other harnesses too, including, 748 \begin{itemize} 650 \begin{itemize}[leftmargin=*] 749 651 \item 750 652 calling a function with a parameter like \lstinline{x} and an argument of the \lstinline{xp} type, … … 762 664 The table treats symbolic identity (Same/Different on rows) 763 665 apart from value equality (Equal/Unequal on columns). 764 \begin{itemize} 666 \begin{itemize}[leftmargin=*] 765 667 \item 766 668 The expressions \lstinline{1}, \lstinline{0+1} and \lstinline{n} … … 781 683 \end{figure} 782 684 783 784 \VRef[Figure]{f:DimexprRuleCompare} gives a case-by-case comparison of the consequences of these rule sets. 785 It demonstrates that the \CFA false alarms occur in the same cases as C treats unsafe. 786 It also shows that C-incompatibilities only occur in cases that C treats unsafe. 787 788 789 The conservatism of the new rule set can leave a programmer needing a recourse, 790 when needing to use a dimension expression whose stability argument 791 is more subtle than current-state analysis. 685 \begin{comment} 686 Given that the above check 687 \begin{itemize} 688 \item 689 Is internal type @char[999]@ type-compatible with internal type @char[n]@? 690 \end{itemize} 691 answers false, discussion turns to how I got the \CFA compiler to produce this answer. 692 In its preexisting form, the type system had a buggy approximation of the C rules. 693 To implement the new \CFA rules, I added one further step. 694 \begin{itemize} 695 \item 696 Is @999@ compatible with @n@? 697 \end{itemize} 698 This question applies to a pair of expressions, where the earlier question applies to types. 699 An expression-compatibility question is a new addition to the \CFA compiler, and occurs in the context of dimension expressions, and possibly enumerations assigns, which must be unique. 700 701 % TODO: ensure these compiler implementation matters are treated under \CFA compiler background: type unification, cost calculation, GenPoly. 702 703 The relevant technical component of the \CFA compiler is the standard type-unification within the type resolver. 704 \begin{cfa} 705 example 706 \end{cfa} 707 I added rules for continuing this unification into expressions that occur within types. 708 It is still fundamentally doing \emph{type} unification because it is participating in binding type variables, and not participating in binding any variables that stand in for expression fragments (for there is no such sort of variable in \CFA's analysis.) 709 An unfortunate fact about the \CFA compiler's preexisting implementation is that type unification suffers from two forms of duplication. 710 711 In detail, the first duplication has (many of) the unification rules stated twice. 712 As a result, my additions for dimension expressions are stated twice. 713 The extra statement of the rules occurs in the @GenPoly@ module, where concrete types like @array( int, 5 )@\footnote{ 714 Again, the presentation is simplified 715 by leaving the \lstinline{array} macro unexpanded.} 716 are lowered into corresponding C types @struct __conc_array_1234@ (the suffix being a generated index). 717 In this case, the struct's definition contains fields that hardcode the argument values of @float@ and @5@. 718 The next time an @array( -, - )@ concrete instance is encountered, it checks if the previous @struct __conc_array_1234@ is suitable for it. 719 Yes, for another occurrence of @array( int, 5 )@; 720 no, for examples like @array( int, 42 )@ or @array( rational(int), 5 )@. 721 In the first example, it must reject the reuse hypothesis for a dimension-@5@ and a dimension-@42@ instance. 722 723 The second duplication has unification (proper) being invoked at two stages of expression resolution. 724 As a result, my added rule set needs to handle more cases than the preceding discussion motivates. 725 In the program 726 \begin{cfa} 727 void @f@( double ); // overload 728 forall( T & ) void @f@( T & ); // overload 729 void g( int n ) { 730 array( float, n + 1 ) x; 731 f(x); // overloaded 732 } 733 \end{cfa} 734 when resolving a function call to @g@, the first unification stage compares the type @T@ of the parameter with @array( float, n + 1 )@, of the argument. 735 \PAB{TODO: finish.} 736 737 The actual rules for comparing two dimension expressions are conservative. 738 To answer, ``yes, consider this pair of expressions to be matching,'' 739 is to imply, ``all else being equal, allow an array with length calculated by $e_1$ 740 to be passed to a function expecting a length-$e_2$ array.''\footnote{ 741 TODO: Deal with directionality, that I'm doing exact-match, no ``at least as long as,'' no subtyping. 742 Should it be an earlier scoping principle? Feels like it should matter in more places than here.} 743 So, a ``yes'' answer must represent a guarantee that both expressions evaluate the 744 same result, while a ``no'' can tolerate ``they might, but we're not sure'', 745 provided that practical recourses are available 746 to let programmers express better knowledge. 747 The new rule-set in the current release is, in fact, extremely conservative. 748 I chose to keep things simple, 749 and allow future needs to drive adding additional complexity, within the new framework. 750 751 For starters, the original motivating example's rejection is not based on knowledge that the @xp@ length of (the literal) 999 is value-unequal to the (obvious) runtime value of the variable @n@, which is the @x@ length. 752 Rather, the analysis assumes a variable's value can be anything, and so there can be no guarantee that its value is 999. 753 So, a variable and a literal can never match. 754 755 TODO: Discuss the interaction of this dimension hoisting with the challenge of extra unification for cost calculation 756 \end{comment} 757 758 The conservatism of the new rule set can leave a programmer needing a recourse, when needing to use a dimension expression whose stability argument is more subtle than current-state analysis. 792 759 This recourse is to declare an explicit constant for the dimension value. 793 Consider these two dimension expressions, 794 whose reuses are rejected by the blunt current-state rules: 795 \begin{cfa} 796 void f( int & nr, const int nv ) { 797 float x[nr]; 798 float (*xp)[nr] = &x; // reject: nr varying (no references) 799 float y[nv + 1]; 800 float (*yp)[nv + 1] = &y; // reject: ?+? unpredictable (no functions) 760 Consider these two dimension expressions, whose uses are rejected by the blunt current-state rules: 761 \begin{cfa} 762 void f( int @&@ nr, @const@ int nv ) { 763 float x[@nr@]; 764 float (*xp)[@nr@] = &x; // reject: nr varying (no references) 765 float y[@nv + 1@]; 766 float (*yp)[@nv + 1@] = &y; // reject: ?+? unpredictable (no functions) 801 767 } 802 768 \end{cfa} 803 769 Yet, both dimension expressions are reused safely. 804 The @nr@ reference is never written, not volatile 805 and control does not leave the function between the uses. 806 The name @?+?@ resolves to a function that is quite predictable. 807 Here, the programmer can add the constant declarations (cast does not work): 770 The @nr@ reference is never written, not volatile meaning no implicit code (load) between declarations, and control does not leave the function between the uses. 771 As well, the build-in @?+?@ function is predictable. 772 To make these cases work, the programmer must add the follow constant declarations (cast does not work): 808 773 \begin{cfa} 809 774 void f( int & nr, const int nv ) { … … 819 784 achieved by adding a superfluous ``snapshot it as of now'' directive. 820 785 821 The snapshot ting trick is also used by thetranslation, though to achieve a different outcome.786 The snapshot trick is also used by the \CFA translation, though to achieve a different outcome. 822 787 Rather obviously, every array must be subscriptable, even a bizarre one: 823 788 \begin{cfa} 824 array( float, rand(10) ) x; 825 x[0]; // 10% chance of bound-check failure 826 \end{cfa} 827 Less obvious is that the mechanism of subscripting is a function call, 828 which must communicate length accurately. 829 The bound-check above (callee logic) must use the actual allocated length of @x@, 830 without mistakenly reevaluating the dimension expression, @rand(10)@. 789 array( float, @rand(10)@ ) x; 790 x[@0@]; // 10% chance of bound-check failure 791 \end{cfa} 792 Less obvious is that the mechanism of subscripting is a function call, which must communicate length accurately. 793 The bound-check above (callee logic) must use the actual allocated length of @x@, without mistakenly reevaluating the dimension expression, @rand(10)@. 831 794 Adjusting the example to make the function's use of length more explicit: 832 795 \begin{cfa} 833 forall 834 void f( T * x ) { sout | sizeof( *x); }796 forall( T * ) 797 void f( T * x ) { sout | sizeof( *x ); } 835 798 float x[ rand(10) ]; 836 799 f( x ); … … 840 803 void f( size_t __sizeof_T, void * x ) { sout | __sizeof_T; } 841 804 \end{cfa} 842 the translation must callthe dimension argument twice:805 the translation calls the dimension argument twice: 843 806 \begin{cfa} 844 807 float x[ rand(10) ]; 845 808 f( rand(10), &x ); 846 809 \end{cfa} 847 Rather, the translationis:810 The correct form is: 848 811 \begin{cfa} 849 812 size_t __dim_x = rand(10); … … 851 814 f( __dim_x, &x ); 852 815 \end{cfa} 853 The occurrence of this dimension hoisting during translation was in the preexisting\CFA compiler.854 But its cases werebuggy, particularly with determining, ``Can hoisting the expression be skipped here?'', for skipping this hoisting is clearly desirable in some cases.855 For example, when the programmer has already done so manually. \PAB{I don't know what this means.}816 Dimension hoisting already existed in the \CFA compiler. 817 But its was buggy, particularly with determining, ``Can hoisting the expression be skipped here?'', for skipping this hoisting is clearly desirable in some cases. 818 For example, when a programmer has already hoisted to perform an optimiation to prelude duplicate code (expression) and/or expression evaluation. 856 819 In the new implementation, these cases are correct, harmonized with the accept/reject criteria. 857 858 TODO: Discuss the interaction of this dimension hoisting with the challenge of extra unification for cost calculation859 820 860 821 … … 863 824 864 825 A multidimensional array implementation has three relevant levels of abstraction, from highest to lowest, where the array occupies \emph{contiguous memory}. 865 \begin{enumerate} 826 \begin{enumerate}[leftmargin=*] 866 827 \item 867 828 Flexible-stride memory: … … 1100 1061 Preexisting \CFA mechanisms achieve this requirement, but with poor performance. 1101 1062 Furthermore, advanced array users need an exception to the basic mechanism, which does not occur with other aggregates. 1102 Hence, arrays introduce sub leties in supporting an element's lifecycle.1063 Hence, arrays introduce subtleties in supporting an element's lifecycle. 1103 1064 1104 1065 The preexisting \CFA support for contained-element lifecycle is based on recursive occurrences of the object-type (@otype@) pseudo-trait. … … 1319 1280 The @worker@ type is designed this way to work with the threading system. 1320 1281 A thread type forks a thread at the end of each constructor and joins with it at the start of each destructor. 1321 But a @worker@ cannot begin its forked-th ead work without knowing its @id@.1282 But a @worker@ cannot begin its forked-thread work without knowing its @id@. 1322 1283 Therefore, there is a conflict between the implicit actions of the builtin @thread@ type and a user's desire to defer these actions. 1323 1284 … … 1460 1421 1461 1422 The \CFA array and the field of ``array language'' comparators all leverage dependent types to improve on the expressiveness over C and Java, accommodating examples such as: 1462 \begin{itemize} 1423 \begin{itemize}[leftmargin=*] 1463 1424 \item a \emph{zip}-style operation that consumes two arrays of equal length 1464 1425 \item a \emph{map}-style operation whose produced length matches the consumed length … … 1544 1505 The details in this presentation aren't meant to be taken too precisely as suggestions for how it should look in \CFA. 1545 1506 But the example shows these abilities: 1546 \begin{itemize} 1507 \begin{itemize}[leftmargin=*] 1547 1508 \item a built-in way (the @is_enum@ trait) for a generic routine to require enumeration-like information about its instantiating type 1548 1509 \item an implicit implementation of the trait whenever a user-written enum occurs (@weekday@'s declaration implies @is_enum@)
Note:
See TracChangeset
for help on using the changeset viewer.