Changeset caa649b for doc/papers/general
- Timestamp:
- Mar 6, 2018, 12:11:11 PM (8 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- 520145b, e5d4e5c, e6c5e79
- Parents:
- 094476d (diff), 1feb535f (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. - Location:
- doc/papers/general
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/papers/general/Paper.tex
r094476d rcaa649b 13 13 \usepackage{pslatex} % reduce size of san serif font 14 14 \usepackage[plainpages=false,pdfpagelabels,pdfpagemode=UseNone,pagebackref=true,breaklinks=true,colorlinks=true,linkcolor=blue,citecolor=blue,urlcolor=blue]{hyperref} 15 \urlstyle{sf} 16 \usepackage{breakurl} 15 17 16 18 \setlength{\textheight}{9in} … … 199 201 The C programming language is a foundational technology for modern computing with millions of lines of code implementing everything from commercial operating-systems to hobby projects. 200 202 This installation base and the programmers producing it represent a massive software-engineering investment spanning decades and likely to continue for decades more. 201 The TIOBE~\cite{TIOBE} ranks the top 5 most popular programming languages as: Java 16\%, \Textbf{C 7\%}, \Textbf{\CC 5\%}, \Csharp 4\%, Python 4\% = 36\%, where the next 50 languages are less than 3\% each with a long tail.203 The TIOBE~\cite{TIOBE} ranks the top 5 most \emph{popular} programming languages as: Java 15\%, \Textbf{C 12\%}, \Textbf{\CC 5.5\%}, Python 5\%, \Csharp 4.5\% = 42\%, where the next 50 languages are less than 4\% each with a long tail. 202 204 The top 3 rankings over the past 30 years are: 203 205 \begin{center} … … 205 207 \lstDeleteShortInline@% 206 208 \begin{tabular}{@{}rccccccc@{}} 207 & 201 7 & 2012 & 2007 & 2002 & 1997 & 1992 & 1987\\ \hline208 Java & 1 & 1 & 1 & 1 & 12 & - & -\\209 \Textbf{C} & \Textbf{2}& \Textbf{2}& \Textbf{2}& \Textbf{2}& \Textbf{1}& \Textbf{1}& \Textbf{1}\\210 \CC & 3 & 3 & 3 & 3 & 2 & 2 & 4\\209 & 2018 & 2013 & 2008 & 2003 & 1998 & 1993 & 1988 \\ \hline 210 Java & 1 & 2 & 1 & 1 & 18 & - & - \\ 211 \Textbf{C}& \Textbf{2} & \Textbf{1} & \Textbf{2} & \Textbf{2} & \Textbf{1} & \Textbf{1} & \Textbf{1} \\ 212 \CC & 3 & 4 & 3 & 3 & 2 & 2 & 5 \\ 211 213 \end{tabular} 212 214 \lstMakeShortInline@% … … 227 229 \CFA is currently implemented as a source-to-source translator from \CFA to the gcc-dialect of C~\cite{GCCExtensions}, allowing it to leverage the portability and code optimizations provided by gcc, meeting goals (1)--(3). 228 230 Ultimately, a compiler is necessary for advanced features and optimal performance. 229 230 This paper identifies shortcomings in existing approaches to generic and variadic data types in C-like languages and presents a design for generic and variadic types avoiding those shortcomings. 231 All of the features discussed in this paper are working, unless a feature states it is a future feature for completion. 232 233 234 \section{Polymorphic Functions} 235 236 \CFA introduces both ad-hoc and parametric polymorphism to C, with a design originally formalized by Ditchfield~\cite{Ditchfield92}, and first implemented by Bilson~\cite{Bilson03}. 237 Shortcomings are identified in existing approaches to generic and variadic data types in C-like languages and how these shortcomings are avoided in \CFA. 231 238 Specifically, the solution is both reusable and type-checked, as well as conforming to the design goals of \CFA with ergonomic use of existing C abstractions. 232 The new constructs are empirically compared with both standard C and \CC; the results show the new design is comparable in performance. 233 234 \section{Polymorphic Functions} 235 236 \CFA introduces both ad-hoc and parametric polymorphism to C, with a design originally formalized by Ditchfield~\cite{Ditchfield92}, and first implemented by Bilson~\cite{Bilson03}. 239 The new constructs are empirically compared with C and \CC approaches via performance experiments in Section~\ref{sec:eval}. 240 237 241 238 242 \subsection{Name Overloading} 239 243 \label{s:NameOverloading} 244 245 \begin{quote} 246 There are only two hard things in Computer Science: cache invalidation and \emph{naming things} -- Phil Karlton 247 \end{quote} 240 248 C already has a limited form of ad-hoc polymorphism in the form of its basic arithmetic operators, which apply to a variety of different types using identical syntax. 241 249 \CFA extends the built-in operator overloading by allowing users to define overloads for any function, not just operators, and even any variable; … … 245 253 246 254 \begin{cfa} 247 int max(int a, int b) { return a < b ? b : a; } // (1) 248 double max(double a, double b) { return a < b ? b : a; } // (2) 249 250 int max = INT_MAX; // (3) 251 double max = DBL_MAX; // (4) 252 253 max(7, -max); $\C{// uses (1) and (3), by matching int from constant 7}$ 254 max(max, 3.14); $\C{// uses (2) and (4), by matching double from constant 3.14}$ 255 256 //max(max, -max); $\C{// ERROR: ambiguous}$ 257 int m = max(max, -max); $\C{// uses (1) once and (3) twice, by matching return type}$ 258 \end{cfa} 259 260 \Celeven did add @_Generic@ expressions, which can be used in preprocessor macros to provide a form of ad-hoc polymorphism; however, this polymorphism is both functionally and ergonomically inferior to \CFA name overloading. 255 int max = 2147483647; $\C[3.75in]{// (1)}$ 256 double max = 1.7976931348623157E+308; $\C{// (2)}$ 257 int max( int a, int b ) { return a < b ? b : a; } $\C{// (3)}$ 258 double max( double a, double b ) { return a < b ? b : a; } $\C{// (4)}\CRT$ 259 max( 7, -max ); $\C{// uses (3) and (1), by matching int from constant 7}$ 260 max( max, 3.14 ); $\C{// uses (4) and (2), by matching double from constant 3.14}$ 261 max( max, -max ); $\C{// ERROR: ambiguous}$ 262 int m = max( max, -max ); $\C{// uses (3) and (1) twice, by matching return type}$ 263 \end{cfa} 264 \CFA maximizes the ability to reuse names to aggressively address the naming problem. 265 In some cases, hundreds of names can be reduced to tens, resulting in a significant cognitive reduction for a programmer. 266 In the above, the name @max@ has a consistent meaning, and a programmer only needs to remember the single concept: maximum. 267 To prevent significant ambiguities, \CFA uses the return type in selecting overloads, \eg in the assignment to @m@, the compiler use @m@'s type to unambiguously select the most appropriate call to function @max@ (as does Ada). 268 As is shown later, there are a number of situations where \CFA takes advantage of available type information to disambiguate, where other programming languages generate ambiguities. 269 270 \Celeven added @_Generic@ expressions, which can be used in preprocessor macros to provide a form of ad-hoc polymorphism; however, this polymorphism is both functionally and ergonomically inferior to \CFA name overloading. 261 271 The macro wrapping the generic expression imposes some limitations; as an example, it could not implement the example above, because the variables @max@ would collide with the functions @max@. 262 272 Ergonomic limitations of @_Generic@ include the necessity to put a fixed list of supported types in a single place and manually dispatch to appropriate overloads, as well as possible namespace pollution from the functions dispatched to, which must all have distinct names. 263 Though name-overloading removes a major use-case for @_Generic@ expressions, \CFA does implement@_Generic@ for backwards-compatibility purposes. \TODO{actually implement that}273 Though name-overloading removes a major use-case for @_Generic@ expressions, \CFA implements @_Generic@ for backwards-compatibility purposes. \TODO{actually implement that} 264 274 265 275 % http://fanf.livejournal.com/144696.html … … 288 298 For example, the function @twice@ can be defined using the \CFA syntax for operator overloading: 289 299 \begin{cfa} 290 forall( otype T `| { T ?+?(T, T); }` ) T twice( T x ) { return x +x; } $\C{// ? denotes operands}$300 forall( otype T `| { T ?+?(T, T); }` ) T twice( T x ) { return x `+` x; } $\C{// ? denotes operands}$ 291 301 int val = twice( twice( 3.7 ) ); 292 302 \end{cfa} … … 343 353 \begin{cfa} 344 354 forall( otype T | { int ?<?( T, T ); } ) void qsort( const T * arr, size_t size ) { /* use C qsort */ } 345 { int ?<?( double x, double y ) { return x `>` y; } $\C{// locally override behaviour}$ 355 { 356 int ?<?( double x, double y ) { return x `>` y; } $\C{// locally override behaviour}$ 346 357 qsort( vals, size ); $\C{// descending sort}$ 347 358 } … … 414 425 \section{Generic Types} 415 426 416 One of the known shortcomings of standard C is that it does not providereusable type-safe abstractions for generic data structures and algorithms.427 A significant shortcoming of standard C is the lack of reusable type-safe abstractions for generic data structures and algorithms. 417 428 Broadly speaking, there are three approaches to implement abstract data-structures in C. 418 429 One approach is to write bespoke data-structures for each context in which they are needed. 419 430 While this approach is flexible and supports integration with the C type-checker and tooling, it is also tedious and error-prone, especially for more complex data structures. 420 A second approach is to use @void *@--based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@ ; an approach which does allow reuse of code forcommon functionality.421 However, basing all polymorphism on @void *@ eliminates the type-checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that would not otherwise be needed.431 A second approach is to use @void *@--based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allows reuse of code with common functionality. 432 However, basing all polymorphism on @void *@ eliminates the type-checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is not otherwise needed. 422 433 A third approach to generic code is to use preprocessor macros, which does allow the generated code to be both generic and type-checked, but errors may be difficult to interpret. 423 434 Furthermore, writing and using preprocessor macros can be unnatural and inflexible. … … 434 445 }; 435 446 forall( otype T ) T value( pair( const char *, T ) p ) { return p.second; } 436 forall( dtype F, otype T ) T value _p( pair( F *, T * ) p ) { return *p.second; }447 forall( dtype F, otype T ) T value( pair( F *, T * ) p ) { return *p.second; } 437 448 438 449 pair( const char *, int ) p = { "magic", 42 }; 439 int magic= value( p );450 int i = value( p ); 440 451 pair( void *, int * ) q = { 0, &p.second }; 441 magic = value_p( q );452 i = value( q ); 442 453 double d = 1.0; 443 454 pair( double *, double * ) r = { &d, &d }; 444 d = value _p( r );455 d = value( r ); 445 456 \end{cfa} 446 457 … … 589 600 [ double ] foo$\(_2\)$( int ); 590 601 void bar( int, double, double ); 591 bar( foo( 3 ), foo( 3 ) );602 `bar`( foo( 3 ), foo( 3 ) ); 592 603 \end{cfa} 593 604 The type-resolver only has the tuple return-types to resolve the call to @bar@ as the @foo@ parameters are identical, which involves unifying the possible @foo@ functions with @bar@'s parameter list. … … 835 846 Since @sum@\(_0\) does not accept any arguments, it is not a valid candidate function for the call @sum(10, 20, 30)@. 836 847 In order to call @sum@\(_1\), @10@ is matched with @x@, and the argument resolution moves on to the argument pack @rest@, which consumes the remainder of the argument list and @Params@ is bound to @[20, 30]@. 837 The process continues un itl @Params@ is bound to @[]@, requiring an assertion @int sum()@, which matches @sum@\(_0\) and terminates the recursion.848 The process continues until @Params@ is bound to @[]@, requiring an assertion @int sum()@, which matches @sum@\(_0\) and terminates the recursion. 838 849 Effectively, this algorithm traces as @sum(10, 20, 30)@ $\rightarrow$ @10 + sum(20, 30)@ $\rightarrow$ @10 + (20 + sum(30))@ $\rightarrow$ @10 + (20 + (30 + sum()))@ $\rightarrow$ @10 + (20 + (30 + 0))@. 839 850 … … 979 990 \section{Control Structures} 980 991 981 \CFA identifies missing and problematic control structures in C, and extends and modifies these control structures to increase functionality and safety. 992 \CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds to control structures to increase functionality and safety. 993 994 995 \subsection{\texorpdfstring{\LstKeywordStyle{if} Statement}{if Statement}} 996 997 The @if@ expression allows declarations, similar to @for@ declaration expression: 998 \begin{cfa} 999 if ( int x = f() ) ... $\C{// x != 0}$ 1000 if ( int x = f(), y = g() ) ... $\C{// x != 0 \&\& y != 0}$ 1001 if ( int x = f(), y = g(); `x < y` ) ... $\C{// relational expression}$ 1002 \end{cfa} 1003 Unless a relational expression is specified, each variable is compared not equal to 0, which is the standard semantics for the @if@ expression, and the results are combined using the logical @&&@ operator.\footnote{\CC only provides a single declaration always compared not equal to 0.} 1004 The scope of the declaration(s) is local to the @if@ statement but exist within both the ``then'' and ``else'' clauses. 1005 1006 1007 \subsection{\texorpdfstring{\LstKeywordStyle{switch} Statement}{switch Statement}} 1008 1009 There are a number of deficiencies with the C @switch@ statements: enumerating @case@ lists, placement of @case@ clauses, scope of the switch body, and fall through between case clauses. 1010 1011 C has no shorthand for specifying a list of case values, whether the list is non-contiguous or contiguous\footnote{C provides this mechanism via fall through.}. 1012 \CFA provides a shorthand for a non-contiguous list: 1013 \begin{cquote} 1014 \lstDeleteShortInline@% 1015 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 1016 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1017 \begin{cfa} 1018 case 2, 10, 34, 42: 1019 \end{cfa} 1020 & 1021 \begin{cfa} 1022 case 2: case 10: case 34: case 42: 1023 \end{cfa} 1024 \end{tabular} 1025 \lstMakeShortInline@% 1026 \end{cquote} 1027 for a contiguous list:\footnote{gcc provides the same mechanism with awkward syntax, \lstinline@2 ... 42@, where spaces are required around the ellipse.} 1028 \begin{cquote} 1029 \lstDeleteShortInline@% 1030 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 1031 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1032 \begin{cfa} 1033 case 2~42: 1034 \end{cfa} 1035 & 1036 \begin{cfa} 1037 case 2: case 3: ... case 41: case 42: 1038 \end{cfa} 1039 \end{tabular} 1040 \lstMakeShortInline@% 1041 \end{cquote} 1042 and a combination: 1043 \begin{cfa} 1044 case -12~-4, -1~5, 14~21, 34~42: 1045 \end{cfa} 1046 1047 C allows placement of @case@ clauses \emph{within} statements nested in the @switch@ body (see Duff's device~\cite{Duff83}); 1048 \begin{cfa} 1049 switch ( i ) { 1050 case 0: 1051 for ( int i = 0; i < 10; i += 1 ) { 1052 ... 1053 `case 1:` // no initialization of loop index 1054 ... 1055 } 1056 } 1057 \end{cfa} 1058 \CFA precludes this form of transfer into a control structure because it causes undefined behaviour, especially with respect to missed initialization, and provides very limited functionality. 1059 1060 C allows placement of declaration within the @switch@ body and unreachable code at the start, resulting in undefined behaviour: 1061 \begin{cfa} 1062 switch ( x ) { 1063 `int y = 1;` $\C{// unreachable initialization}$ 1064 `x = 7;` $\C{// unreachable code without label/branch}$ 1065 case 0: 1066 ... 1067 `int z = 0;` $\C{// unreachable initialization, cannot appear after case}$ 1068 z = 2; 1069 case 1: 1070 `x = z;` $\C{// without fall through, z is undefined}$ 1071 } 1072 \end{cfa} 1073 \CFA allows the declaration of local variables, \eg @y@, at the start of the @switch@ with scope across the entire @switch@ body, \ie all @case@ clauses. 1074 \CFA disallows the declaration of local variable, \eg @z@, directly within the @switch@ body, because a declaration cannot occur immediately after a @case@ since a label can only be attached to a statement, and the use of @z@ is undefined in @case 1@ as neither storage allocation nor initialization may have occurred. 1075 1076 C @switch@ provides multiple entry points into the statement body, but once an entry point is selected, control continues across \emph{all} @case@ clauses until the end of the @switch@ body, called \newterm{fall through}; 1077 @case@ clauses are made disjoint by the @break@ statement. 1078 While the ability to fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in many errors from missing @break@ statements. 1079 For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through (see Figure~\ref{f:ChooseSwitchStatements}). 1080 Collectively, these enhancements reduce programmer burden and increase readability and safety. 1081 1082 \begin{figure} 1083 \centering 1084 \lstDeleteShortInline@% 1085 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1086 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1087 \begin{cfa} 1088 `choose` ( day ) { 1089 case Mon~Thu: // program 1090 1091 case Fri: // program 1092 wallet += pay; 1093 `fallthrough;` 1094 case Sat: // party 1095 wallet -= party; 1096 1097 case Sun: // rest 1098 1099 default: // error 1100 } 1101 \end{cfa} 1102 & 1103 \begin{cfa} 1104 switch ( day ) { 1105 case Mon: case Tue: case Wed: case Thu: // program 1106 `break;` 1107 case Fri: // program 1108 wallet += pay; 1109 1110 case Sat: // party 1111 wallet -= party; 1112 `break;` 1113 case Sun: // rest 1114 `break;` 1115 default: // error 1116 } 1117 \end{cfa} 1118 \end{tabular} 1119 \lstMakeShortInline@% 1120 \caption{\lstinline|choose| versus \lstinline|switch| Statements} 1121 \label{f:ChooseSwitchStatements} 1122 \end{figure} 1123 1124 \begin{comment} 1125 Forgotten @break@ statements at the end of @switch@ cases are a persistent sort of programmer error in C, and the @break@ statements themselves introduce visual clutter and an un-C-like keyword-based block delimiter. 1126 \CFA addresses this error by introducing a @choose@ statement, which works identically to a @switch@ except that its default end-of-case behaviour is to break rather than to fall through for all non-empty cases. 1127 Since empty cases like @case 7:@ in @case 7: case 11:@ still have fall-through semantics and explicit @break@ is still allowed at the end of a @choose@ case, many idiomatic uses of @switch@ in standard C can be converted to @choose@ statements by simply changing the keyword. 1128 Where fall-through is desired for a non-empty case, it can be specified with the new @fallthrough@ statement, making @choose@ equivalently powerful to @switch@, but more concise in the common case where most non-empty cases end with a @break@ statement, as in the example below: 1129 1130 \begin{cfa} 1131 choose( i ) { 1132 case 2: 1133 printf("even "); 1134 fallthrough; 1135 case 3: case 5: case 7: 1136 printf("small prime\n"); 1137 case 4,6,8,9: 1138 printf("small composite\n"); 1139 case 13~19: 1140 printf("teen\n"); 1141 default: 1142 printf("something else\n"); 1143 } 1144 \end{cfa} 1145 \end{comment} 982 1146 983 1147 … … 1039 1203 } else { 1040 1204 ... goto `LIF`; ... 1041 } `L 3:` ;1205 } `LIF:` ; 1042 1206 } `LS:` ; 1043 1207 } `LC:` ; … … 1089 1253 1090 1254 1091 \subsection{\texorpdfstring{Enhanced \LstKeywordStyle{switch} Statement}{Enhanced switch Statement}} 1092 1093 There are a number of deficiencies with the C @switch@ statements: enumerating @case@ lists, placement of @case@ clauses, scope of the switch body, and fall through between case clauses. 1094 1095 C has no shorthand for specifying a list of case values, whether the list is non-contiguous or contiguous\footnote{C provides this mechanism via fall through.}. 1096 \CFA provides a shorthand for a non-contiguous list: 1255 \subsection{Exception Handling} 1256 1257 The following framework for \CFA exception handling is in place, excluding a run-time type information and dynamic casts. 1258 \CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling}). 1259 Both mechanisms provide dynamic call to a handler using dynamic name-lookup, where fix-up has dynamic return and recovery has static return from the handler. 1260 \CFA restricts exception types to those defined by aggregate type @exception@. 1261 The form of the raise dictates the set of handlers examined during propagation: \newterm{resumption propagation} (@resume@) only examines resumption handlers (@catchResume@); \newterm{terminating propagation} (@throw@) only examines termination handlers (@catch@). 1262 If @resume@ or @throw@ have no exception type, it is a reresume/rethrow, meaning the currently exception continues propagation. 1263 If there is no current exception, the reresume/rethrow results in a runtime error. 1264 1265 \begin{figure} 1097 1266 \begin{cquote} 1098 1267 \lstDeleteShortInline@% 1099 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 1100 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1101 \begin{cfa} 1102 case 2, 10, 34, 42: 1103 \end{cfa} 1104 & 1105 \begin{cfa} 1106 case 2: case 10: case 34: case 42: 1268 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1269 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{Resumption}} & \multicolumn{1}{c}{\textbf{Termination}} \\ 1270 \begin{cfa} 1271 `exception R { int fix; };` 1272 void f() { 1273 R r; 1274 ... `resume( r );` ... 1275 ... r.fix // control does return here after handler 1276 } 1277 `try` { 1278 ... f(); ... 1279 } `catchResume( R r )` { 1280 ... r.fix = ...; // return correction to raise 1281 } // dynamic return to _Resume 1282 \end{cfa} 1283 & 1284 \begin{cfa} 1285 `exception T {};` 1286 void f() { 1287 1288 ... `throw( T{} );` ... 1289 // control does NOT return here after handler 1290 } 1291 `try` { 1292 ... f(); ... 1293 } `catch( T t )` { 1294 ... // recover and continue 1295 } // static return to next statement 1107 1296 \end{cfa} 1108 1297 \end{tabular} 1109 1298 \lstMakeShortInline@% 1110 1299 \end{cquote} 1111 for a contiguous list:\footnote{gcc provides the same mechanism with awkward syntax, \lstinline@2 ... 42@, where spaces are required around the ellipse.} 1300 \caption{\CFA Exception Handling} 1301 \label{f:CFAExceptionHandling} 1302 \end{figure} 1303 1304 The set of exception types in a list of catch clause may include both a resumption and termination handler: 1305 \begin{cfa} 1306 try { 1307 ... resume( `R{}` ); ... 1308 } catchResume( `R` r ) { ... throw( R{} ); ... } $\C{\color{red}// H1}$ 1309 catch( `R` r ) { ... } $\C{\color{red}// H2}$ 1310 1311 \end{cfa} 1312 The resumption propagation raises @R@ and the stack is not unwound; 1313 the exception is caught by the @catchResume@ clause and handler H1 is invoked. 1314 The termination propagation in handler H1 raises @R@ and the stack is unwound; 1315 the exception is caught by the @catch@ clause and handler H2 is invoked. 1316 The termination handler is available because the resumption propagation did not unwind the stack. 1317 1318 An additional feature is conditional matching in a catch clause: 1319 \begin{cfa} 1320 try { 1321 ... write( `datafile`, ... ); ... $\C{// may throw IOError}$ 1322 ... write( `logfile`, ... ); ... 1323 } catch ( IOError err; `err.file == datafile` ) { ... } $\C{// handle datafile error}$ 1324 catch ( IOError err; `err.file == logfile` ) { ... } $\C{// handle logfile error}$ 1325 catch ( IOError err ) { ... } $\C{// handler error from other files}$ 1326 \end{cfa} 1327 where the throw inserts the failing file-handle in the I/O exception. 1328 Conditional catch cannot be trivially mimicked by other mechanisms because once an exception is caught, handler clauses in that @try@ statement are no longer eligible.. 1329 1330 The resumption raise can specify an alternate stack on which to raise an exception, called a \newterm{nonlocal raise}: 1331 \begin{cfa} 1332 resume( $\emph{exception-type}$, $\emph{alternate-stack}$ ) 1333 resume( $\emph{alternate-stack}$ ) 1334 \end{cfa} 1335 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another coroutine or task~\cite{Delisle18}. 1336 Nonlocal raise is restricted to resumption to provide the exception handler the greatest flexibility because processing the exception does not unwind its stack, allowing it to continue after the handle returns. 1337 1338 To facilitate nonlocal exception, \CFA provides dynamic enabling and disabling of nonlocal exception-propagation. 1339 The constructs for controlling propagation of nonlocal exceptions are the @enable@ and the @disable@ blocks: 1112 1340 \begin{cquote} 1113 1341 \lstDeleteShortInline@% 1114 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 1115 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1116 \begin{cfa} 1117 case 2~42: 1118 \end{cfa} 1119 & 1120 \begin{cfa} 1121 case 2: case 3: ... case 41: case 42: 1342 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1343 \begin{cfa} 1344 enable $\emph{exception-type-list}$ { 1345 // allow non-local resumption 1346 } 1347 \end{cfa} 1348 & 1349 \begin{cfa} 1350 disable $\emph{exception-type-list}$ { 1351 // disallow non-local resumption 1352 } 1122 1353 \end{cfa} 1123 1354 \end{tabular} 1124 1355 \lstMakeShortInline@% 1125 1356 \end{cquote} 1126 and a combination: 1127 \begin{cfa} 1128 case -12~-4, -1~5, 14~21, 34~42: 1129 \end{cfa} 1130 1131 C allows placement of @case@ clauses \emph{within} statements nested in the @switch@ body (see Duff's device~\cite{Duff83}); 1132 \begin{cfa} 1133 switch ( i ) { 1134 case 0: 1135 for ( int i = 0; i < 10; i += 1 ) { 1136 ... 1137 `case 1:` // no initialization of loop index 1138 ... 1139 } 1140 } 1141 \end{cfa} 1142 \CFA precludes this form of transfer into a control structure because it causes undefined behaviour, especially with respect to missed initialization, and provides very limited functionality. 1143 1144 C allows placement of declaration within the @switch@ body and unreachable code at the start, resulting in undefined behaviour: 1145 \begin{cfa} 1146 switch ( x ) { 1147 `int y = 1;` $\C{// unreachable initialization}$ 1148 `x = 7;` $\C{// unreachable code without label/branch}$ 1149 case 0: 1150 ... 1151 `int z = 0;` $\C{// unreachable initialization, cannot appear after case}$ 1152 z = 2; 1153 case 1: 1154 `x = z;` $\C{// without fall through, z is undefined}$ 1155 } 1156 \end{cfa} 1157 \CFA allows the declaration of local variables, \eg @y@, at the start of the @switch@ with scope across the entire @switch@ body, \ie all @case@ clauses. 1158 \CFA disallows the declaration of local variable, \eg @z@, directly within the @switch@ body, because a declaration cannot occur immediately after a @case@ since a label can only be attached to a statement, and the use of @z@ is undefined in @case 1@ as neither storage allocation nor initialization may have occurred. 1159 1160 C @switch@ provides multiple entry points into the statement body, but once an entry point is selected, control continues across \emph{all} @case@ clauses until the end of the @switch@ body, called \newterm{fall through}; 1161 @case@ clauses are made disjoint by the @break@ statement. 1162 While the ability to fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in many errors from missing @break@ statements. 1163 For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through: 1164 \begin{cquote} 1165 \lstDeleteShortInline@% 1166 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 1167 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1168 \begin{cfa} 1169 `choose` ( day ) { 1170 case Mon~Thu: // program 1171 1172 case Fri: // program 1173 wallet += pay; 1174 `fallthrough;` 1175 case Sat: // party 1176 wallet -= party; 1177 1178 case Sun: // rest 1179 1180 default: // error 1181 } 1182 \end{cfa} 1183 & 1184 \begin{cfa} 1185 switch ( day ) { 1186 case Mon: case Tue: case Wed: case Thu: // program 1187 `break;` 1188 case Fri: // program 1189 wallet += pay; 1190 1191 case Sat: // party 1192 wallet -= party; 1193 `break;` 1194 case Sun: // rest 1195 `break;` 1196 default: // error 1197 } 1198 \end{cfa} 1199 \end{tabular} 1200 \lstMakeShortInline@% 1201 \end{cquote} 1202 Collectively, these enhancements reduce programmer burden and increase readability and safety. 1203 1204 \begin{comment} 1205 Forgotten @break@ statements at the end of @switch@ cases are a persistent sort of programmer error in C, and the @break@ statements themselves introduce visual clutter and an un-C-like keyword-based block delimiter. 1206 \CFA addresses this error by introducing a @choose@ statement, which works identically to a @switch@ except that its default end-of-case behaviour is to break rather than to fall through for all non-empty cases. 1207 Since empty cases like @case 7:@ in @case 7: case 11:@ still have fall-through semantics and explicit @break@ is still allowed at the end of a @choose@ case, many idiomatic uses of @switch@ in standard C can be converted to @choose@ statements by simply changing the keyword. 1208 Where fall-through is desired for a non-empty case, it can be specified with the new @fallthrough@ statement, making @choose@ equivalently powerful to @switch@, but more concise in the common case where most non-empty cases end with a @break@ statement, as in the example below: 1209 1210 \begin{cfa} 1211 choose( i ) { 1212 case 2: 1213 printf("even "); 1214 fallthrough; 1215 case 3: case 5: case 7: 1216 printf("small prime\n"); 1217 case 4,6,8,9: 1218 printf("small composite\n"); 1219 case 13~19: 1220 printf("teen\n"); 1221 default: 1222 printf("something else\n"); 1223 } 1224 \end{cfa} 1225 \end{comment} 1357 The arguments for @enable@/@disable@ specify the exception types allowed to be propagated or postponed, respectively. 1358 Specifying no exception type is shorthand for specifying all exception types. 1359 Both @enable@ and @disable@ blocks can be nested, turning propagation on/off on entry, and on exit, the specified exception types are restored to their prior state. 1360 1361 Finally, \CFA provides a Java like @finally@ clause after the catch clauses: 1362 \begin{cfa} 1363 try { 1364 ... f(); ... 1365 // catchResume or catch clauses 1366 } `finally` { 1367 // house keeping 1368 } 1369 \end{cfa} 1370 The finally clause is always executed, i.e., if the try block ends normally or if an exception is raised. 1371 If an exception is raised and caught, the handler is run before the finally clause. 1372 Like a destructor (see Section~\ref{s:ConstructorsDestructors}), a finally clause can raise an exception but not if there is an exception being propagated. 1373 Mimicking the @finally@ clause with mechanisms like RAII is non-trivially when there are multiple types and local accesses. 1226 1374 1227 1375 … … 1238 1386 S s, as[10]; 1239 1387 \end{cfa} 1240 However, routines manipulating aggregates must repeat the aggregate name to access its containing fields:1388 However, functions manipulating aggregates must repeat the aggregate name to access its containing fields: 1241 1389 \begin{cfa} 1242 1390 void f( S s ) { … … 1256 1404 } 1257 1405 \end{C++} 1258 Object-oriented nesting of member routines in a \lstinline[language=C++]@class@ allows eliding \lstinline[language=C++]@this->@ because of lexical scoping.1406 Object-oriented nesting of member functions in a \lstinline[language=C++]@class@ allows eliding \lstinline[language=C++]@this->@ because of lexical scoping. 1259 1407 However, for other aggregate parameters, qualification is necessary: 1260 1408 \begin{cfa} … … 1286 1434 'with' '(' $\emph{expression-list}$ ')' $\emph{compound-statement}$ 1287 1435 \end{cfa} 1288 and may appear as the body of a routine or nested within a routinebody.1436 and may appear as the body of a function or nested within a function body. 1289 1437 Each expression in the expression-list provides a type and object. 1290 1438 The type must be an aggregate type. … … 1313 1461 Qualification or a cast is used to disambiguate. 1314 1462 1315 There is an interesting problem between parameters and the routine@with@, \eg:1463 There is an interesting problem between parameters and the function @with@, \eg: 1316 1464 \begin{cfa} 1317 1465 void ?{}( S & s, int i ) with ( s ) { $\C{// constructor}$ … … 1319 1467 } 1320 1468 \end{cfa} 1321 Here, the assignment @s.i = i@ means @s.i = s.i@, which is meaningless, and there is no mechanism to qualify the parameter @i@, making the assignment impossible using the routine@with@.1469 Here, the assignment @s.i = i@ means @s.i = s.i@, which is meaningless, and there is no mechanism to qualify the parameter @i@, making the assignment impossible using the function @with@. 1322 1470 To solve this problem, parameters are treated like an initialized aggregate: 1323 1471 \begin{cfa} … … 1327 1475 } params; 1328 1476 \end{cfa} 1329 and implicitly opened \emph{after} a routineopen, to give them higher priority:1477 and implicitly opened \emph{after} a function open, to give them higher priority: 1330 1478 \begin{cfa} 1331 1479 void ?{}( S & s, int i ) with ( s ) `with( $\emph{\color{red}params}$ )` { … … 1355 1503 1356 1504 1357 \subsection{Exception Handling}1358 1359 The following framework for \CFA exception handling is in place, excluding a run-time type information and dynamic casts.1360 \CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling}).1361 Both mechanisms provide dynamic call to a handler using dynamic name-lookup, where fix-up has dynamic return and recovery has static return from the handler.1362 \CFA restricts exception types to those defined by aggregate type @exception@.1363 The form of the raise dictates the set of handlers examined during propagation: \newterm{resumption propagation} (@resume@) only examines resumption handlers (@catchResume@); \newterm{terminating propagation} (@throw@) only examines termination handlers (@catch@).1364 If @resume@ or @throw@ have no exception type, it is a reresume/rethrow, meaning the currently exception continues propagation.1365 If there is no current exception, the reresume/rethrow results in a runtime error.1366 1367 \begin{figure}1368 \begin{cquote}1369 \lstDeleteShortInline@%1370 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}}1371 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{Resumption}} & \multicolumn{1}{c}{\textbf{Recovery}} \\1372 \begin{cfa}1373 `exception R { int fix; };`1374 void f() {1375 R r;1376 ... `resume( r );` ...1377 ... r.fix // control does return here after handler1378 }1379 `try` {1380 ... f(); ...1381 } `catchResume( R r )` {1382 ... r.fix = ...; // return correction to raise1383 } // dynamic return to _Resume1384 \end{cfa}1385 &1386 \begin{cfa}1387 `exception T {};`1388 void f() {1389 1390 ... `throw( T{} );` ...1391 // control does NOT return here after handler1392 }1393 `try` {1394 ... f(); ...1395 } `catch( T t )` {1396 ... // recover and continue1397 } // static return to next statement1398 \end{cfa}1399 \end{tabular}1400 \lstMakeShortInline@%1401 \end{cquote}1402 \caption{\CFA Exception Handling}1403 \label{f:CFAExceptionHandling}1404 \end{figure}1405 1406 The set of exception types in a list of catch clause may include both a resumption and termination handler:1407 \begin{cfa}1408 try {1409 ... resume( `R{}` ); ...1410 } catchResume( `R` r ) { ... throw( R{} ); ... } $\C{\color{red}// H1}$1411 catch( `R` r ) { ... } $\C{\color{red}// H2}$1412 1413 \end{cfa}1414 The resumption propagation raises @R@ and the stack is not unwound;1415 the exception is caught by the @catchResume@ clause and handler H1 is invoked.1416 The termination propagation in handler H1 raises @R@ and the stack is unwound;1417 the exception is caught by the @catch@ clause and handler H2 is invoked.1418 The termination handler is available because the resumption propagation did not unwind the stack.1419 1420 An additional feature is conditional matching in a catch clause:1421 \begin{cfa}1422 try {1423 ... write( `datafile`, ... ); ... $\C{// may throw IOError}$1424 ... write( `logfile`, ... ); ...1425 } catch ( IOError err; `err.file == datafile` ) { ... } $\C{// handle datafile error}$1426 catch ( IOError err; `err.file == logfile` ) { ... } $\C{// handle logfile error}$1427 catch ( IOError err ) { ... } $\C{// handler error from other files}$1428 \end{cfa}1429 where the throw inserts the failing file-handle in the I/O exception.1430 Conditional catch cannot be trivially mimicked by other mechanisms because once an exception is caught, handler clauses in that @try@ statement are no longer eligible..1431 1432 The resumption raise can specify an alternate stack on which to raise an exception, called a \newterm{nonlocal raise}:1433 \begin{cfa}1434 resume( $\emph{exception-type}$, $\emph{alternate-stack}$ )1435 resume( $\emph{alternate-stack}$ )1436 \end{cfa}1437 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another coroutine or task~\cite{Delisle18}.1438 Nonlocal raise is restricted to resumption to provide the exception handler the greatest flexibility because processing the exception does not unwind its stack, allowing it to continue after the handle returns.1439 1440 To facilitate nonlocal exception, \CFA provides dynamic enabling and disabling of nonlocal exception-propagation.1441 The constructs for controlling propagation of nonlocal exceptions are the @enable@ and the @disable@ blocks:1442 \begin{cquote}1443 \lstDeleteShortInline@%1444 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}1445 \begin{cfa}1446 enable $\emph{exception-type-list}$ {1447 // allow non-local resumption1448 }1449 \end{cfa}1450 &1451 \begin{cfa}1452 disable $\emph{exception-type-list}$ {1453 // disallow non-local resumption1454 }1455 \end{cfa}1456 \end{tabular}1457 \lstMakeShortInline@%1458 \end{cquote}1459 The arguments for @enable@/@disable@ specify the exception types allowed to be propagated or postponed, respectively.1460 Specifying no exception type is shorthand for specifying all exception types.1461 Both @enable@ and @disable@ blocks can be nested, turning propagation on/off on entry, and on exit, the specified exception types are restored to their prior state.1462 1463 Finally, \CFA provides a Java like @finally@ clause after the catch clauses:1464 \begin{cfa}1465 try {1466 ... f(); ...1467 // catchResume or catch clauses1468 } `finally` {1469 // house keeping1470 }1471 \end{cfa}1472 The finally clause is always executed, i.e., if the try block ends normally or if an exception is raised.1473 If an exception is raised and caught, the handler is run before the finally clause.1474 Like a destructor (see Section~\ref{s:ConstructorsDestructors}), a finally clause can raise an exception but not if there is an exception being propagated.1475 Mimicking the @finally@ clause with mechanisms like RAII is non-trivially when there are multiple types and local accesses.1476 1477 1478 1505 \section{Declarations} 1479 1506 … … 1503 1530 Is this an array of 5 pointers to integers or a pointer to an array of 5 integers? 1504 1531 If there is any doubt, it implies productivity and safety issues even for basic programs. 1505 Another example of confusion results from the fact that a routine name and its parameters are embedded within the return type, mimicking the way the return value is used at the routine's call site.1506 For example, a routinereturning a pointer to an array of integers is defined and used in the following way:1532 Another example of confusion results from the fact that a function name and its parameters are embedded within the return type, mimicking the way the return value is used at the function's call site. 1533 For example, a function returning a pointer to an array of integers is defined and used in the following way: 1507 1534 \begin{cfa} 1508 1535 int `(*`f`())[`5`]` {...}; $\C{// definition}$ 1509 1536 ... `(*`f`())[`3`]` += 1; $\C{// usage}$ 1510 1537 \end{cfa} 1511 Essentially, the return type is wrapped around the routinename in successive layers (like an onion).1538 Essentially, the return type is wrapped around the function name in successive layers (like an onion). 1512 1539 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice. 1513 1540 1514 \CFA provides its own type, variable and routinedeclarations, using a different syntax.1541 \CFA provides its own type, variable and function declarations, using a different syntax. 1515 1542 The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right. 1516 1543 The qualifiers have the same meaning but are ordered left to right to specify a variable's type. … … 1540 1567 \end{cquote} 1541 1568 The only exception is bit field specification, which always appear to the right of the base type. 1542 % Specifically, the character @*@ is used to indicate a pointer, square brackets @[@\,@]@ are used to represent an array or function return value, and parentheses @()@ are used to indicate a routineparameter.1569 % Specifically, the character @*@ is used to indicate a pointer, square brackets @[@\,@]@ are used to represent an array or function return value, and parentheses @()@ are used to indicate a function parameter. 1543 1570 However, unlike C, \CFA type declaration tokens are distributed across all variables in the declaration list. 1544 1571 For instance, variables @x@ and @y@ of type pointer to integer are defined in \CFA as follows: … … 1626 1653 \lstMakeShortInline@% 1627 1654 \end{cquote} 1628 Specifiers must appear at the start of a \CFA routinedeclaration\footnote{\label{StorageClassSpecifier}1655 Specifiers must appear at the start of a \CFA function declaration\footnote{\label{StorageClassSpecifier} 1629 1656 The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature.~\cite[\S~6.11.5(1)]{C11}}. 1630 1657 1631 The new declaration syntax can be used in other contexts where types are required, \eg casts and the pseudo- routine@sizeof@:1658 The new declaration syntax can be used in other contexts where types are required, \eg casts and the pseudo-function @sizeof@: 1632 1659 \begin{cquote} 1633 1660 \lstDeleteShortInline@% … … 1647 1674 \end{cquote} 1648 1675 1649 The syntax of the new routine prototype declaration follows directly from the new routinedefinition syntax;1676 The syntax of the new function-prototype declaration follows directly from the new function-definition syntax; 1650 1677 as well, parameter names are optional, \eg: 1651 1678 \begin{cfa} … … 1656 1683 [ * int, int ] j ( int ); $\C{// returning pointer to int and int, with int parameter}$ 1657 1684 \end{cfa} 1658 This syntax allows a prototype declaration to be created by cutting and pasting source text from the routinedefinition header (or vice versa).1659 Like C, it is possible to declare multiple routine-prototypes in a single declaration, where the return type is distributed across \emph{all} routinenames in the declaration list, \eg:1685 This syntax allows a prototype declaration to be created by cutting and pasting source text from the function-definition header (or vice versa). 1686 Like C, it is possible to declare multiple function-prototypes in a single declaration, where the return type is distributed across \emph{all} function names in the declaration list, \eg: 1660 1687 \begin{cquote} 1661 1688 \lstDeleteShortInline@% … … 1672 1699 \lstMakeShortInline@% 1673 1700 \end{cquote} 1674 where \CFA allows the last routinein the list to define its body.1675 1676 The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg:1677 \begin{cfa} 1678 * [ int x ] () fp; $\C{// pointer to routinereturning int with no parameters}$1679 * [ * int ] ( int y ) gp; $\C{// pointer to routinereturning pointer to int with int parameter}$1680 * [ ] ( int, char ) hp; $\C{// pointer to routinereturning no result with int and char parameters}$1681 * [ * int, int ] ( int ) jp; $\C{// pointer to routinereturning pointer to int and int, with int parameter}$1682 \end{cfa} 1683 Note, a routinename cannot be specified:1684 \begin{cfa} 1685 * [ int x ] f () fp; $\C{// routinename "f" is disallowed}$1701 where \CFA allows the last function in the list to define its body. 1702 1703 The syntax for pointers to \CFA functions specifies the pointer name on the right, \eg: 1704 \begin{cfa} 1705 * [ int x ] () fp; $\C{// pointer to function returning int with no parameters}$ 1706 * [ * int ] ( int y ) gp; $\C{// pointer to function returning pointer to int with int parameter}$ 1707 * [ ] ( int, char ) hp; $\C{// pointer to function returning no result with int and char parameters}$ 1708 * [ * int, int ] ( int ) jp; $\C{// pointer to function returning pointer to int and int, with int parameter}$ 1709 \end{cfa} 1710 Note, a function name cannot be specified: 1711 \begin{cfa} 1712 * [ int x ] f () fp; $\C{// function name "f" is disallowed}$ 1686 1713 \end{cfa} 1687 1714 … … 1903 1930 Destruction parameters are useful for specifying storage-management actions, such as de-initialize but not deallocate.}. 1904 1931 \begin{cfa} 1905 struct VLA { 1906 int len, * data; 1907 }; 1908 void ?{}( VLA & vla ) with ( vla ) { $\C{// default constructor}$ 1909 len = 10; data = alloc( len ); $\C{// shallow copy}$ 1910 } 1911 void ^?{}( VLA & vla ) with ( vla ) { $\C{// destructor}$ 1912 free( data ); 1913 } 1932 struct VLA { int len, * data; }; 1933 void ?{}( VLA & vla ) with ( vla ) { len = 10; data = alloc( len ); } $\C{// default constructor}$ 1934 void ^?{}( VLA & vla ) with ( vla ) { free( data ); } $\C{// destructor}$ 1914 1935 { 1915 1936 VLA x; $\C{// implicit: ?\{\}( x );}$ 1916 1937 } $\C{// implicit: ?\^{}\{\}( x );}$ 1917 1938 \end{cfa} 1918 (Note, the example is purposely kept simple by using shallow-copy semantics.)1919 1939 @VLA@ is a \newterm{managed type}\footnote{ 1920 1940 A managed type affects the runtime environment versus a self-contained type.}: a type requiring a non-trivial constructor or destructor, or with a field of a managed type. … … 1924 1944 \CFA also provides syntax for \newterm{initialization} and \newterm{copy}: 1925 1945 \begin{cfa} 1926 void ?{}( VLA & vla, int size, char fill ) with ( vla ) { 1946 void ?{}( VLA & vla, int size, char fill ) with ( vla ) { $\C{// initialization}$ 1927 1947 len = size; data = alloc( len, fill ); 1928 1948 } 1929 void ?{}( VLA & vla, VLA other ) { $\C{// copy }$1949 void ?{}( VLA & vla, VLA other ) { $\C{// copy, shallow}$ 1930 1950 vla.len = other.len; vla.data = other.data; 1931 1951 } 1932 1952 \end{cfa} 1953 (Note, the example is purposely kept simple by using shallow-copy semantics.) 1933 1954 An initialization constructor-call has the same syntax as a C initializer, except the initialization values are passed as arguments to a matching constructor (number and type of paremeters). 1934 1955 \begin{cfa} … … 1944 1965 \begin{cfa} 1945 1966 { 1946 VLA x, y = { 20, 0x01 }, z = y;1947 // implicit: ?{}( x ); ?{}( y, 20, 0x01 ); ?{}( z, y ); z points to y1967 VLA x, y = { 20, 0x01 }, z = y; $\C{// z points to y}$ 1968 // ?{}( x ); ?{}( y, 20, 0x01 ); ?{}( z, y ); 1948 1969 ^x{}; $\C{// deallocate x}$ 1949 1970 x{}; $\C{// reallocate x}$ … … 1952 1973 y{ x }; $\C{// reallocate y, points to x}$ 1953 1974 x{}; $\C{// reallocate x, not pointing to y}$ 1954 // implicit:^?{}(z); ^?{}(y); ^?{}(x);1975 // ^?{}(z); ^?{}(y); ^?{}(x); 1955 1976 } 1956 1977 \end{cfa} … … 1983 2004 C already includes limited polymorphism for literals -- @0@ can be either an integer or a pointer literal, depending on context, while the syntactic forms of literals of the various integer and float types are very similar, differing from each other only in suffix. 1984 2005 In keeping with the general \CFA approach of adding features while respecting the ``C-style'' of doing things, C's polymorphic constants and typed literal syntax are extended to interoperate with user-defined types, while maintaining a backwards-compatible semantics. 1985 A trivial example is allowing the underscore to separate prefixes, digits, and suffixes in all \CFA constants, as in Ada, \eg @0x`_`1.ffff`_`ffff`_`p`_`128`_`l@. 2006 A trivial example is allowing the underscore, as in Ada, to separate prefixes, digits, and suffixes in all \CFA constants, \eg @0x`_`1.ffff`_`ffff`_`p`_`128`_`l@. 2007 2008 2009 \subsection{Integral Suffixes} 2010 2011 Additional integral suffixes are added to cover all the integral types and lengths. 2012 \begin{cquote} 2013 \lstDeleteShortInline@% 2014 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}} 2015 \begin{cfa} 2016 20`_hh` // signed char 2017 21`_hhu` // unsigned char 2018 22`_h` // signed short int 2019 23`_uh` // unsigned short int 2020 24`z` // size_t 2021 \end{cfa} 2022 & 2023 \begin{cfa} 2024 20`_L8` // int8_t 2025 21`_ul8` // uint8_t 2026 22`_l16` // int16_t 2027 23`_ul16` // uint16_t 2028 24`_l32` // int32_t 2029 \end{cfa} 2030 & 2031 \begin{cfa} 2032 25`_ul32` // uint32_t 2033 26`_l64` // int64_t 2034 27`_l64u` // uint64_t 2035 26`_L128` // int128 2036 27`_L128u` // unsigned int128 2037 \end{cfa} 2038 \end{tabular} 2039 \lstMakeShortInline@% 2040 \end{cquote} 1986 2041 1987 2042 … … 2000 2055 2001 2056 2002 \subsection{Integral Suffixes} 2003 2004 Additional integral suffixes are added to cover all the integral types and lengths. 2005 \begin{cquote} 2057 \subsection{User Literals} 2058 2059 For readability, it is useful to associate units to scale literals, \eg weight (stone, pound, kilogram) or time (seconds, minutes, hours). 2060 The left of Figure~\ref{f:UserLiteral} shows the \CFA alternative call-syntax (literal argument before function name), using the backquote, to convert basic literals into user literals. 2061 The backquote is a small character, making the unit (function name) predominate. 2062 For examples, the multi-precision integers in Section~\ref{s:MultiPrecisionIntegers} make use of user literals: 2063 {\lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}} 2064 \begin{cfa} 2065 y = 9223372036854775807L|`mp| * 18446744073709551615UL|`mp|; 2066 y = "12345678901234567890123456789"|`mp| + "12345678901234567890123456789"|`mp|; 2067 \end{cfa} 2068 Because \CFA uses a standard function, all types and literals are applicable, as well as overloading and conversions. 2069 }% 2070 2071 The right of Figure~\ref{f:UserLiteral} shows the equivalent \CC version using the underscore for the call-syntax. 2072 However, \CC restricts the types, \eg @unsigned long long int@ and @long double@ to represent integral and floating literals. 2073 After which, user literals must match (no conversions); 2074 hence, it is necessary to overload the unit with all appropriate types. 2075 Finally, the use of the single quote as a separator is restricted to digits, precluding its use in the literal prefix or suffix, and causes problems with most IDEs, which must be extended to deal with this alternate use of the single quote. 2076 2077 \begin{figure} 2078 \centering 2079 \lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}} 2006 2080 \lstDeleteShortInline@% 2007 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}} 2008 \begin{cfa} 2009 20_hh // signed char 2010 21_hhu // unsigned char 2011 22_h // signed short int 2012 23_uh // unsigned short int 2013 24z // size_t 2014 \end{cfa} 2015 & 2016 \begin{cfa} 2017 20_L8 // int8_t 2018 21_ul8 // uint8_t 2019 22_l16 // int16_t 2020 23_ul16 // uint16_t 2021 24_l32 // int32_t 2022 \end{cfa} 2023 & 2024 \begin{cfa} 2025 25_ul32 // uint32_t 2026 26_l64 // int64_t 2027 27_l64u // uint64_t 2028 26_L128 // int128 2029 27_L128u // unsigned int128 2081 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 2082 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{\CC}} \\ 2083 \begin{cfa} 2084 struct W { 2085 double stones; 2086 }; 2087 void ?{}( W & w ) { w.stones = 0; } 2088 void ?{}( W & w, double w ) { w.stones = w; } 2089 W ?+?( W l, W r ) { 2090 return (W){ l.stones + r.stones }; 2091 } 2092 W |?`st|( double w ) { return (W){ w }; } 2093 W |?`lb|( double w ) { return (W){ w / 14.0 }; } 2094 W |?`kg|( double w ) { return (W) { w * 0.16 }; } 2095 2096 2097 2098 int main() { 2099 W w, heavy = { 20 }; 2100 w = 155|`lb|; 2101 w = 0b_1111|`st|; 2102 w = 0_233|`lb|; 2103 w = 0x_9b_u|`kg|; 2104 w = 5.5|`st| + 8|`kg| + 25.01|`lb| + heavy; 2105 } 2106 \end{cfa} 2107 & 2108 \begin{cfa} 2109 struct W { 2110 double stones; 2111 W() { stones = 0.0; } 2112 W( double w ) { stones = w; } 2113 }; 2114 W operator+( W l, W r ) { 2115 return W( l.stones + r.stones ); 2116 } 2117 W |operator"" _st|( unsigned long long int w ) { return W( w ); } 2118 W |operator"" _lb|( unsigned long long int w ) { return W( w / 14.0 ); } 2119 W |operator"" _kg|( unsigned long long int w ) { return W( w * 0.16 ); } 2120 W |operator"" _st|( long double w ) { return W( w ); } 2121 W |operator"" _lb|( long double w ) { return W( w / 14.0 ); } 2122 W |operator"" _kg|( long double w ) { return W( w * 0.16 ); } 2123 int main() { 2124 W w, heavy = { 20 }; 2125 w = 155|_lb|; 2126 w = 0b1111|_lb|; // error, binary unsupported 2127 w = 0${\color{red}'}$233|_lb|; // quote separator 2128 w = 0x9b|_kg|; 2129 w = 5.5d|_st| + 8|_kg| + 25.01|_lb| + heavy; 2130 } 2030 2131 \end{cfa} 2031 2132 \end{tabular} 2032 2133 \lstMakeShortInline@% 2033 \end{cquote} 2034 2035 2036 \subsection{Units} 2037 2038 Alternative call syntax (literal argument before routine name) to convert basic literals into user literals. 2039 2040 {\lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}} 2041 \begin{cfa} 2042 struct Weight { double stones; }; 2043 void ?{}( Weight & w ) { w.stones = 0; } $\C{// operations}$ 2044 void ?{}( Weight & w, double w ) { w.stones = w; } 2045 Weight ?+?( Weight l, Weight r ) { return (Weight){ l.stones + r.stones }; } 2046 2047 Weight |?`st|( double w ) { return (Weight){ w }; } $\C{// backquote for units}$ 2048 Weight |?`lb|( double w ) { return (Weight){ w / 14.0 }; } 2049 Weight |?`kg|( double w ) { return (Weight) { w * 0.1575}; } 2050 2051 int main() { 2052 Weight w, heavy = { 20 }; $\C{// 20 stone}$ 2053 w = 155|`lb|; 2054 w = 0x_9b_u|`lb|; $\C{// hexadecimal unsigned weight (155)}$ 2055 w = 0_233|`lb|; $\C{// octal weight (155)}$ 2056 w = 5|`st| + 8|`kg| + 25|`lb| + heavy; 2057 } 2058 \end{cfa} 2059 }% 2134 \caption{User Literal} 2135 \label{f:UserLiteral} 2136 \end{figure} 2060 2137 2061 2138 … … 2067 2144 In many cases, the interface is an inline wrapper providing overloading during compilation but zero cost at runtime. 2068 2145 The following sections give a glimpse of the interface reduction to many C libraries. 2069 In many cases, @signed@/@unsigned@ @char@ and @short@ routines are available (but not shown) to ensure expression computations remain in a single type, as conversions can distort results.2146 In many cases, @signed@/@unsigned@ @char@, @short@, and @_Complex@ functions are available (but not shown) to ensure expression computations remain in a single type, as conversions can distort results. 2070 2147 2071 2148 … … 2095 2172 \begin{cquote} 2096 2173 \lstDeleteShortInline@% 2097 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 2098 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 2174 \lstset{basicstyle=\linespread{0.9}\sf\small} 2175 \begin{tabular}{@{}l@{\hspace{0.5\parindentlnth}}l@{}} 2176 \multicolumn{1}{c@{\hspace{0.5\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 2099 2177 \begin{cfa} 2100 2178 MIN 2101 2179 MAX 2102 M_PI2103 M_E2104 \end{cfa} 2105 & 2106 \begin{cfa} 2107 SCHAR_MIN, CHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN, 2108 SCHAR_MAX, UCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX, 2109 M_PI, M_PIl , M_CPI, M_CPIl,2110 M_E, M_El , M_CE, M_CEl2180 PI 2181 E 2182 \end{cfa} 2183 & 2184 \begin{cfa} 2185 SCHAR_MIN, CHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN, FLT_MIN, DBL_MIN, LDBL_MIN 2186 SCHAR_MAX, UCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX, FLT_MAX, DBL_MAX, LDBL_MAX 2187 M_PI, M_PIl 2188 M_E, M_El 2111 2189 \end{cfa} 2112 2190 \end{tabular} … … 2117 2195 \subsection{Math} 2118 2196 2119 C library @math.h@ provides many mathematical routines.2120 \CFA routine overloading is used to condense these mathematical routines, \eg:2197 C library @math.h@ provides many mathematical functions. 2198 \CFA function overloading is used to condense these mathematical functions, \eg: 2121 2199 \begin{cquote} 2122 2200 \lstDeleteShortInline@% … … 2137 2215 \lstMakeShortInline@% 2138 2216 \end{cquote} 2139 The result is a significant reduction in names to access math routines, \eg:2217 The result is a significant reduction in names to access math functions, \eg: 2140 2218 \begin{cquote} 2141 2219 \lstDeleteShortInline@% … … 2156 2234 \lstMakeShortInline@% 2157 2235 \end{cquote} 2158 While \Celeven has type-generic math~\cite[\S~7.25]{C11} in @tgmath.h@ to provide a similar mechanism, these macros are limited, matching a routinename with a single set of floating type(s).2236 While \Celeven has type-generic math~\cite[\S~7.25]{C11} in @tgmath.h@ to provide a similar mechanism, these macros are limited, matching a function name with a single set of floating type(s). 2159 2237 For example, it is impossible to overload @atan@ for both one and two arguments; 2160 instead the names @atan@ and @atan2@ are required .2161 The key observation is that only a restricted set of type-generic macros are provided for a limited set of routinenames, which do not generalize across the type system, as in \CFA.2238 instead the names @atan@ and @atan2@ are required (see Section~\ref{s:NameOverloading}). 2239 The key observation is that only a restricted set of type-generic macros are provided for a limited set of function names, which do not generalize across the type system, as in \CFA. 2162 2240 2163 2241 2164 2242 \subsection{Standard} 2165 2243 2166 C library @stdlib.h@ provides many general routines.2167 \CFA routine overloading is used to condense these utility routines, \eg:2244 C library @stdlib.h@ provides many general functions. 2245 \CFA function overloading is used to condense these utility functions, \eg: 2168 2246 \begin{cquote} 2169 2247 \lstDeleteShortInline@% … … 2184 2262 \lstMakeShortInline@% 2185 2263 \end{cquote} 2186 The result is a significant reduction in names to access utility routines, \eg:2264 The result is a significant reduction in names to access utility functions, \eg: 2187 2265 \begin{cquote} 2188 2266 \lstDeleteShortInline@% … … 2203 2281 \lstMakeShortInline@% 2204 2282 \end{cquote} 2205 In additon, there are polymorphic routines, like @min@ and @max@, which work on any type with operators @?<?@ or @?>?@.2283 In additon, there are polymorphic functions, like @min@ and @max@, which work on any type with operators @?<?@ or @?>?@. 2206 2284 2207 2285 The following shows one example where \CFA \emph{extends} an existing standard C interface to reduce complexity and provide safety. … … 2220 2298 An array may be filled, resized, or aligned. 2221 2299 \end{description} 2222 Table~\ref{t:StorageManagementOperations} shows the capabilities provided by C/\Celeven allocation-routines and how all the capabilities can be combined into two \CFA routines. 2223 2224 \CFA storage-management routines extend the C equivalents by overloading, providing shallow type-safety, and removing the need to specify the base allocation-size. 2225 The following example contrasts \CFA and C storage-allocation operation performing the same operations with the same type safety: 2226 \begin{cquote} 2227 \begin{cfa}[aboveskip=0pt] 2228 size_t dim = 10; $\C{// array dimension}$ 2229 char fill = '\xff'; $\C{// initialization fill value}$ 2230 int * ip; 2231 \end{cfa} 2232 \lstDeleteShortInline@% 2233 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 2234 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 2235 \begin{cfa} 2236 ip = alloc(); 2237 ip = alloc( fill ); 2238 ip = alloc( dim ); 2239 ip = alloc( dim, fill ); 2240 ip = alloc( ip, 2 * dim ); 2241 ip = alloc( ip, 4 * dim, fill ); 2242 2243 ip = align_alloc( 16 ); 2244 ip = align_alloc( 16, fill ); 2245 ip = align_alloc( 16, dim ); 2246 ip = align_alloc( 16, dim, fill ); 2247 \end{cfa} 2248 & 2249 \begin{cfa} 2250 ip = (int *)malloc( sizeof( int ) ); 2251 ip = (int *)malloc( sizeof( int ) ); memset( ip, fill, sizeof( int ) ); 2252 ip = (int *)malloc( dim * sizeof( int ) ); 2253 ip = (int *)malloc( sizeof( int ) ); memset( ip, fill, dim * sizeof( int ) ); 2254 ip = (int *)realloc( ip, 2 * dim * sizeof( int ) ); 2255 ip = (int *)realloc( ip, 4 * dim * sizeof( int ) ); memset( ip, fill, 4 * dim * sizeof( int ) ); 2256 2257 ip = memalign( 16, sizeof( int ) ); 2258 ip = memalign( 16, sizeof( int ) ); memset( ip, fill, sizeof( int ) ); 2259 ip = memalign( 16, dim * sizeof( int ) ); 2260 ip = memalign( 16, dim * sizeof( int ) ); memset( ip, fill, dim * sizeof( int ) ); 2261 \end{cfa} 2262 \end{tabular} 2263 \lstMakeShortInline@% 2264 \end{cquote} 2265 Variadic @new@ (see Section~\ref{sec:variadic-tuples}) cannot support the same overloading because extra parameters are for initialization. 2266 Hence, there are @new@ and @anew@ routines for single and array variables, and the fill value is the arguments to the constructor, \eg: 2267 \begin{cfa} 2268 struct S { int i, j; }; 2269 void ?{}( S & s, int i, int j ) { s.i = i; s.j = j; } 2270 S * s = new( 2, 3 ); $\C{// allocate storage and run constructor}$ 2271 S * as = anew( dim, 2, 3 ); $\C{// each array element initialized to 2, 3}$ 2272 \end{cfa} 2273 Note, \CC can only initialization array elements via the default constructor. 2274 2275 Finally, the \CFA memory-allocator has \newterm{sticky properties} for dynamic storage: fill and alignment are remembered with an object's storage in the heap. 2276 When a @realloc@ is performed, the sticky properties are respected, so that new storage is correctly aligned and initialized with the fill character. 2300 Table~\ref{t:StorageManagementOperations} shows the capabilities provided by C/\Celeven allocation-functions and how all the capabilities can be combined into two \CFA functions. 2301 \CFA storage-management functions extend the C equivalents by overloading, providing shallow type-safety, and removing the need to specify the base allocation-size. 2302 Figure~\ref{f:StorageAllocation} contrasts \CFA and C storage-allocation operation performing the same operations with the same type safety. 2277 2303 2278 2304 \begin{table} … … 2300 2326 \end{table} 2301 2327 2328 \begin{figure} 2329 \centering 2330 \begin{cquote} 2331 \begin{cfa}[aboveskip=0pt] 2332 size_t dim = 10; $\C{// array dimension}$ 2333 char fill = '\xff'; $\C{// initialization fill value}$ 2334 int * ip; 2335 \end{cfa} 2336 \lstDeleteShortInline@% 2337 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 2338 \multicolumn{1}{c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 2339 \begin{cfa} 2340 ip = alloc(); 2341 ip = alloc( fill ); 2342 ip = alloc( dim ); 2343 ip = alloc( dim, fill ); 2344 ip = alloc( ip, 2 * dim ); 2345 ip = alloc( ip, 4 * dim, fill ); 2346 2347 ip = align_alloc( 16 ); 2348 ip = align_alloc( 16, fill ); 2349 ip = align_alloc( 16, dim ); 2350 ip = align_alloc( 16, dim, fill ); 2351 \end{cfa} 2352 & 2353 \begin{cfa} 2354 ip = (int *)malloc( sizeof( int ) ); 2355 ip = (int *)malloc( sizeof( int ) ); memset( ip, fill, sizeof( int ) ); 2356 ip = (int *)malloc( dim * sizeof( int ) ); 2357 ip = (int *)malloc( sizeof( int ) ); memset( ip, fill, dim * sizeof( int ) ); 2358 ip = (int *)realloc( ip, 2 * dim * sizeof( int ) ); 2359 ip = (int *)realloc( ip, 4 * dim * sizeof( int ) ); memset( ip, fill, 4 * dim * sizeof( int ) ); 2360 2361 ip = memalign( 16, sizeof( int ) ); 2362 ip = memalign( 16, sizeof( int ) ); memset( ip, fill, sizeof( int ) ); 2363 ip = memalign( 16, dim * sizeof( int ) ); 2364 ip = memalign( 16, dim * sizeof( int ) ); memset( ip, fill, dim * sizeof( int ) ); 2365 \end{cfa} 2366 \end{tabular} 2367 \lstMakeShortInline@% 2368 \end{cquote} 2369 \caption{\CFA versus C Storage-Allocation} 2370 \label{f:StorageAllocation} 2371 \end{figure} 2372 2373 Variadic @new@ (see Section~\ref{sec:variadic-tuples}) cannot support the same overloading because extra parameters are for initialization. 2374 Hence, there are @new@ and @anew@ functions for single and array variables, and the fill value is the arguments to the constructor, \eg: 2375 \begin{cfa} 2376 struct S { int i, j; }; 2377 void ?{}( S & s, int i, int j ) { s.i = i; s.j = j; } 2378 S * s = new( 2, 3 ); $\C{// allocate storage and run constructor}$ 2379 S * as = anew( dim, 2, 3 ); $\C{// each array element initialized to 2, 3}$ 2380 \end{cfa} 2381 Note, \CC can only initialization array elements via the default constructor. 2382 2383 Finally, the \CFA memory-allocator has \newterm{sticky properties} for dynamic storage: fill and alignment are remembered with an object's storage in the heap. 2384 When a @realloc@ is performed, the sticky properties are respected, so that new storage is correctly aligned and initialized with the fill character. 2385 2302 2386 2303 2387 \subsection{I/O} … … 2387 2471 }% 2388 2472 \end{itemize} 2389 There are routines to set and get the separator string, and manipulators to toggle separation on and off in the middle of output.2473 There are functions to set and get the separator string, and manipulators to toggle separation on and off in the middle of output. 2390 2474 2391 2475 … … 2394 2478 2395 2479 \CFA has an interface to the GMP multi-precision signed-integers~\cite{GMP}, similar to the \CC interface provided by GMP. 2396 The \CFA interface wraps GMP routines into operator routines to make programming with multi-precision integers identical to using fixed-sized integers.2480 The \CFA interface wraps GMP functions into operator functions to make programming with multi-precision integers identical to using fixed-sized integers. 2397 2481 The \CFA type name for multi-precision signed-integers is @Int@ and the header file is @gmp@. 2398 2482 The following multi-precision factorial programs contrast using GMP with the \CFA and C interfaces. … … 2439 2523 Since all these languages share a subset essentially comprising standard C, maximal-performance benchmarks would show little runtime variance, other than in length and clarity of source code. 2440 2524 A more illustrative benchmark measures the costs of idiomatic usage of each language's features. 2441 Figure~\ref{fig:BenchmarkTest} shows the \CFA benchmark tests for a generic stack based on a singly linked-list, a generic pair-data-structure, and a variadic @print@ routinesimilar to that in Section~\ref{sec:variadic-tuples}.2525 Figure~\ref{fig:BenchmarkTest} shows the \CFA benchmark tests for a generic stack based on a singly linked-list, a generic pair-data-structure, and a variadic @print@ function similar to that in Section~\ref{sec:variadic-tuples}. 2442 2526 The benchmark test is similar for C and \CC. 2443 2527 The experiment uses element types @int@ and @pair(_Bool, char)@, and pushes $N=40M$ elements on a generic stack, copies the stack, clears one of the stacks, finds the maximum value in the other stack, and prints $N/2$ (to reduce graph height) constants. … … 2446 2530 \begin{cfa}[xleftmargin=3\parindentlnth,aboveskip=0pt,belowskip=0pt] 2447 2531 int main( int argc, char * argv[] ) { 2448 FILE * out = fopen( "cfa-out.txt", "w" ); 2449 int maxi = 0, vali = 42; 2450 stack(int) si, ti; 2451 2452 REPEAT_TIMED( "push_int", N, push( &si, vali ); ) 2453 TIMED( "copy_int", ti = si; ) 2454 TIMED( "clear_int", clear( &si ); ) 2455 REPEAT_TIMED( "pop_int", N, 2456 int xi = pop( &ti ); if ( xi > maxi ) { maxi = xi; } ) 2457 REPEAT_TIMED( "print_int", N/2, print( out, vali, ":", vali, "\n" ); ) 2458 2459 pair(_Bool, char) maxp = { (_Bool)0, '\0' }, valp = { (_Bool)1, 'a' }; 2460 stack(pair(_Bool, char)) sp, tp; 2461 2462 REPEAT_TIMED( "push_pair", N, push( &sp, valp ); ) 2463 TIMED( "copy_pair", tp = sp; ) 2464 TIMED( "clear_pair", clear( &sp ); ) 2465 REPEAT_TIMED( "pop_pair", N, 2466 pair(_Bool, char) xp = pop( &tp ); if ( xp > maxp ) { maxp = xp; } ) 2467 REPEAT_TIMED( "print_pair", N/2, print( out, valp, ":", valp, "\n" ); ) 2468 fclose(out); 2532 ofstream out = { "cfa-out.txt" }; 2533 int max = 0, val = 42; 2534 stack( int ) s, t; 2535 2536 REPEAT_TIMED( "push_int", N, push( s, val ); ) 2537 TIMED( "copy_int", t = s; ) 2538 TIMED( "clear_int", clear( s ); ) 2539 REPEAT_TIMED( "pop_int", N, int v = pop( t ); max = max( v, max ); ) 2540 REPEAT_TIMED( "print_int", N/2, out | val | ':' | val | endl; ) 2541 2542 pair( _Bool, char ) max = { false, '\0' }, val = { true, 'a' }; 2543 stack( pair( _Bool, char ) ) s, t; 2544 2545 REPEAT_TIMED( "push_pair", N, push( s, val ); ) 2546 TIMED( "copy_pair", t = s; ) 2547 TIMED( "clear_pair", clear( s ); ) 2548 REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) v = pop( t ); max = max( v, max ); ) 2549 REPEAT_TIMED( "print_pair", N/2, out | val | ':' | val | endl; ) 2469 2550 } 2470 2551 \end{cfa} … … 2537 2618 \CC is the most similar language to \CFA; 2538 2619 both are extensions to C with source and runtime backwards compatibility. 2539 The fundamental difference is in their engineering approach toC compatibility and programmer expectation.2540 While \CC provides good backwardscompatibility with C, it has a steep learning curve for many of its extensions.2620 The fundamental difference is the engineering approach to maintain C compatibility and programmer expectation. 2621 While \CC provides good compatibility with C, it has a steep learning curve for many of its extensions. 2541 2622 For example, polymorphism is provided via three disjoint mechanisms: overloading, inheritance, and templates. 2542 2623 The overloading is restricted because resolution does not use the return type, inheritance requires learning object-oriented programming and coping with a restricted nominal-inheritance hierarchy, templates cannot be separately compiled resulting in compilation/code bloat and poor error messages, and determining how these mechanisms interact and which to use is confusing. 2543 2624 In contrast, \CFA has a single facility for polymorphic code supporting type-safe separate-compilation of polymorphic functions and generic (opaque) types, which uniformly leverage the C procedural paradigm. 2544 The key mechanism to support separate compilation is \CFA's \emph{explicit} use of assumed properties for a type.2545 Until \CC concepts~\cite{C++Concepts} are standardized (anticipated for \CCtwenty), \CC provides no way to specify the requirements of a generic function in codebeyond compilation errors during template expansion;2625 The key mechanism to support separate compilation is \CFA's \emph{explicit} use of assumed type properties. 2626 Until \CC concepts~\cite{C++Concepts} are standardized (anticipated for \CCtwenty), \CC provides no way to specify the requirements of a generic function beyond compilation errors during template expansion; 2546 2627 furthermore, \CC concepts are restricted to template polymorphism. 2547 2628 … … 2594 2675 2595 2676 2677 \subsection{Control Structures / Declarations / Literals} 2678 2679 2596 2680 \section{Conclusion and Future Work} 2597 2681 … … 2620 2704 2621 2705 The authors would like to recognize the design assistance of Glen Ditchfield, Richard Bilson, and Thierry Delisle on the features described in this paper, and thank Magnus Madsen for feedback in the writing. 2622 %This work is supported in part by a corporate partnership with \grantsponsor{Huawei}{Huawei Ltd.}{http://www.huawei.com}, and Aaron Moss and Peter Buhr are funded by the \grantsponsor{Natural Sciences and Engineering Research Council} of Canada. 2706 This work is supported through a corporate partnership with Huawei Ltd.\ (\url{http://www.huawei.com}), and Aaron Moss and Peter Buhr are funded by the Natural Sciences and Engineering Research Council of Canada. 2707 2623 2708 % the first author's \grantsponsor{NSERC-PGS}{NSERC PGS D}{http://www.nserc-crsng.gc.ca/Students-Etudiants/PG-CS/BellandPostgrad-BelletSuperieures_eng.asp} scholarship. 2624 2709 … … 2640 2725 \CFA 2641 2726 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 2727 forall(otype T) struct stack_node; 2728 forall(otype T) struct stack { 2729 stack_node(T) * head; 2730 }; 2642 2731 forall(otype T) struct stack_node { 2643 2732 T value; 2644 2733 stack_node(T) * next; 2645 2734 }; 2646 forall(otype T) void ?{}( stack(T) * s) { (&s->head){ 0 }; }2647 forall(otype T) void ?{}( stack(T) * s, stack(T) t) {2648 stack_node(T) ** crnt = &s ->head;2735 forall(otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; } 2736 forall(otype T) void ?{}( stack(T) & s, stack(T) t ) { 2737 stack_node(T) ** crnt = &s.head; 2649 2738 for ( stack_node(T) * next = t.head; next; next = next->next ) { 2650 *crnt = ((stack_node(T) *)malloc()){ next->value }; /***/ 2739 stack_node(T) * new_node = ((stack_node(T)*)malloc()); 2740 (*new_node){ next->value }; /***/ 2741 *crnt = new_node; 2651 2742 stack_node(T) * acrnt = *crnt; 2652 2743 crnt = &acrnt->next; … … 2654 2745 *crnt = 0; 2655 2746 } 2656 forall(otype T) stack(T) ?=?( stack(T) * s, stack(T) t) {2657 if ( s ->head == t.head ) return *s;2658 clear( s);2747 forall(otype T) stack(T) ?=?( stack(T) & s, stack(T) t ) { 2748 if ( s.head == t.head ) return s; 2749 clear( s ); 2659 2750 s{ t }; 2660 return *s; 2661 } 2662 forall(otype T) void ^?{}(stack(T) * s) { clear(s); } 2663 forall(otype T) _Bool empty(const stack(T) * s) { return s->head == 0; } 2664 forall(otype T) void push(stack(T) * s, T value) { 2665 s->head = ((stack_node(T) *)malloc()){ value, s->head }; /***/ 2666 } 2667 forall(otype T) T pop(stack(T) * s) { 2668 stack_node(T) * n = s->head; 2669 s->head = n->next; 2670 T x = n->value; 2671 ^n{}; 2672 free(n); 2673 return x; 2674 } 2675 forall(otype T) void clear(stack(T) * s) { 2676 for ( stack_node(T) * next = s->head; next; ) { 2751 return s; 2752 } 2753 forall(otype T) void ^?{}( stack(T) & s) { clear( s ); } 2754 forall(otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; } 2755 forall(otype T) void push( stack(T) & s, T value ) { 2756 stack_node(T) * new_node = ((stack_node(T)*)malloc()); 2757 (*new_node){ value, s.head }; /***/ 2758 s.head = new_node; 2759 } 2760 forall(otype T) T pop( stack(T) & s ) { 2761 stack_node(T) * n = s.head; 2762 s.head = n->next; 2763 T v = n->value; 2764 delete( n ); 2765 return v; 2766 } 2767 forall(otype T) void clear( stack(T) & s ) { 2768 for ( stack_node(T) * next = s.head; next; ) { 2677 2769 stack_node(T) * crnt = next; 2678 2770 next = crnt->next; 2679 delete( crnt);2771 delete( crnt ); 2680 2772 } 2681 s ->head = 0;2773 s.head = 0; 2682 2774 } 2683 2775 \end{cfa} … … 2827 2919 2828 2920 2829 \begin{comment}2830 2831 \subsubsection{bench.h}2832 (\texttt{bench.hpp} is similar.)2833 2834 \lstinputlisting{evaluation/bench.h}2835 2836 \subsection{C}2837 2838 \subsubsection{c-stack.h} ~2839 2840 \lstinputlisting{evaluation/c-stack.h}2841 2842 \subsubsection{c-stack.c} ~2843 2844 \lstinputlisting{evaluation/c-stack.c}2845 2846 \subsubsection{c-pair.h} ~2847 2848 \lstinputlisting{evaluation/c-pair.h}2849 2850 \subsubsection{c-pair.c} ~2851 2852 \lstinputlisting{evaluation/c-pair.c}2853 2854 \subsubsection{c-print.h} ~2855 2856 \lstinputlisting{evaluation/c-print.h}2857 2858 \subsubsection{c-print.c} ~2859 2860 \lstinputlisting{evaluation/c-print.c}2861 2862 \subsubsection{c-bench.c} ~2863 2864 \lstinputlisting{evaluation/c-bench.c}2865 2866 \subsection{\CFA}2867 2868 \subsubsection{cfa-stack.h} ~2869 2870 \lstinputlisting{evaluation/cfa-stack.h}2871 2872 \subsubsection{cfa-stack.c} ~2873 2874 \lstinputlisting{evaluation/cfa-stack.c}2875 2876 \subsubsection{cfa-print.h} ~2877 2878 \lstinputlisting{evaluation/cfa-print.h}2879 2880 \subsubsection{cfa-print.c} ~2881 2882 \lstinputlisting{evaluation/cfa-print.c}2883 2884 \subsubsection{cfa-bench.c} ~2885 2886 \lstinputlisting{evaluation/cfa-bench.c}2887 2888 \subsection{\CC}2889 2890 \subsubsection{cpp-stack.hpp} ~2891 2892 \lstinputlisting[language=c++]{evaluation/cpp-stack.hpp}2893 2894 \subsubsection{cpp-print.hpp} ~2895 2896 \lstinputlisting[language=c++]{evaluation/cpp-print.hpp}2897 2898 \subsubsection{cpp-bench.cpp} ~2899 2900 \lstinputlisting[language=c++]{evaluation/cpp-bench.cpp}2901 2902 \subsection{\CCV}2903 2904 \subsubsection{object.hpp} ~2905 2906 \lstinputlisting[language=c++]{evaluation/object.hpp}2907 2908 \subsubsection{cpp-vstack.hpp} ~2909 2910 \lstinputlisting[language=c++]{evaluation/cpp-vstack.hpp}2911 2912 \subsubsection{cpp-vstack.cpp} ~2913 2914 \lstinputlisting[language=c++]{evaluation/cpp-vstack.cpp}2915 2916 \subsubsection{cpp-vprint.hpp} ~2917 2918 \lstinputlisting[language=c++]{evaluation/cpp-vprint.hpp}2919 2920 \subsubsection{cpp-vbench.cpp} ~2921 2922 \lstinputlisting[language=c++]{evaluation/cpp-vbench.cpp}2923 \end{comment}2924 2925 2921 \end{document} 2926 2922 -
doc/papers/general/evaluation/cfa-bench.c
r094476d rcaa649b 1 #include <stdio.h> 1 #include <fstream> 2 #include <stdlib> 3 #include <stdbool.h> 2 4 #include "bench.h" 3 5 #include "cfa-stack.h" … … 5 7 #include "cfa-print.h" 6 8 7 int main( int argc, char * argv[] ) {8 FILE * out = fopen( "/dev/null", "w" );9 int max i = 0, vali= 42;10 stack( int) si, ti;9 int main( int argc, char * argv[] ) { 10 ofstream out = { "/dev/null" }; 11 int max = 0, val = 42; 12 stack( int ) s, t; 11 13 12 REPEAT_TIMED( "push_int", N, push( &si, vali ); ) 13 TIMED( "copy_int", ti = si; ) 14 TIMED( "clear_int", clear( &si ); ) 15 REPEAT_TIMED( "pop_int", N, 16 int xi = pop( &ti ); 17 if ( xi > maxi ) { maxi = xi; } ) 18 REPEAT_TIMED( "print_int", N/2, print( out, vali, ":", vali, "\n" ); ) 14 REPEAT_TIMED( "push_int", N, push( s, val ); ) 15 TIMED( "copy_int", t = s; ) 16 TIMED( "clear_int", clear( s ); ) 17 REPEAT_TIMED( "pop_int", N, int x = pop( t ); max = max( x, max ); ) 18 REPEAT_TIMED( "print_int", N/2, out | val | ':' | val | endl; ) 19 19 20 pair( _Bool, char) maxp = { (_Bool)0, '\0' }, valp = { (_Bool)1, 'a' };21 stack( pair(_Bool, char)) sp, tp;20 pair( _Bool, char ) max = { (_Bool)false, '\0' }, val = { (_Bool)true, 'a' }; 21 stack( pair( _Bool, char ) ) s, t; 22 22 23 REPEAT_TIMED( "push_pair", N, push( &sp, valp ); ) 24 TIMED( "copy_pair", tp = sp; ) 25 TIMED( "clear_pair", clear( &sp ); ) 26 REPEAT_TIMED( "pop_pair", N, 27 pair(_Bool, char) xp = pop( &tp ); 28 if ( xp > maxp ) { maxp = xp; } ) 29 REPEAT_TIMED( "print_pair", N/2, print( out, valp, ":", valp, "\n" ); ) 30 fclose(out); 23 REPEAT_TIMED( "push_pair", N, push( s, val ); ) 24 TIMED( "copy_pair", t = s; ) 25 TIMED( "clear_pair", clear( s ); ) 26 REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) x = pop( t ); max = max( x, max ); ) 27 REPEAT_TIMED( "print_pair", N/2, out | val | ':' | val | endl; ) 31 28 } -
doc/papers/general/evaluation/cfa-pair.c
r094476d rcaa649b 1 1 #include "cfa-pair.h" 2 #include "fstream" 2 3 3 forall(otype R, otype S 4 forall(otype R, otype S 4 5 | { int ?==?(R, R); int ?<?(R, R); int ?<?(S, S); }) 5 6 int ?<?(pair(R, S) p, pair(R, S) q) { … … 7 8 } 8 9 9 forall(otype R, otype S 10 forall(otype R, otype S 10 11 | { int ?==?(R, R); int ?<?(R, R); int ?<=?(S, S); }) 11 12 int ?<=?(pair(R, S) p, pair(R, S) q) { … … 23 24 } 24 25 25 forall(otype R, otype S 26 forall(otype R, otype S 26 27 | { int ?==?(R, R); int ?>?(R, R); int ?>?(S, S); }) 27 28 int ?>?(pair(R, S) p, pair(R, S) q) { … … 29 30 } 30 31 31 forall(otype R, otype S 32 forall(otype R, otype S 32 33 | { int ?==?(R, R); int ?>?(R, R); int ?>=?(S, S); }) 33 34 int ?>=?(pair(R, S) p, pair(R, S) q) { 34 35 return p.first > q.first || ( p.first == q.first && p.second >= q.second ); 35 36 } 37 38 forall(otype R, otype S) 39 forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, R ); ostype & ?|?( ostype &, S ); }) 40 ostype & ?|?( ostype & os, pair(R, S) p ) { 41 return os | '[' | p.first | ',' | p.second | ']'; 42 } // ?|? -
doc/papers/general/evaluation/cfa-pair.h
r094476d rcaa649b 1 1 #pragma once 2 3 #include "iostream" 2 4 3 5 forall(otype R, otype S) struct pair { … … 27 29 | { int ?==?(R, R); int ?>?(R, R); int ?>=?(S, S); }) 28 30 int ?>=?(pair(R, S) p, pair(R, S) q); 31 32 forall(otype R, otype S) 33 forall(dtype ostype | ostream( ostype ) | { ostype & ?|?( ostype &, pair(R, S) ); }) 34 ostype & ?|?( ostype & os, pair(R, S) ); -
doc/papers/general/evaluation/cfa-stack.c
r094476d rcaa649b 4 4 forall(otype T) struct stack_node { 5 5 T value; 6 stack_node(T) * next;6 stack_node(T) * next; 7 7 }; 8 forall(otype T) void ?{}( stack_node(T) & node, T value, stack_node(T) * next ) { 9 node.value = value; 10 node.next = next; 11 } 8 12 9 forall(otype T) void ?{}( stack(T)* s) { (&s->head){ 0 }; }13 forall(otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; } 10 14 11 forall(otype T) void ?{}(stack(T)* s, stack(T) t) { 12 stack_node(T)** crnt = &s->head; 13 for ( stack_node(T)* next = t.head; next; next = next->next ) { 14 *crnt = ((stack_node(T)*)malloc()){ next->value }; /***/ 15 stack_node(T)* acrnt = *crnt; 15 forall(otype T) void ?{}( stack(T) & s, stack(T) t ) { 16 stack_node(T) ** crnt = &s.head; 17 for ( stack_node(T) * next = t.head; next; next = next->next ) { 18 // *crnt = new( next->value, 0 ); 19 stack_node(T)* new_node = ((stack_node(T)*)malloc()); 20 (*new_node){ next->value }; /***/ 21 *crnt = new_node; 22 stack_node(T) * acrnt = *crnt; 16 23 crnt = &acrnt->next; 17 24 } … … 19 26 } 20 27 21 forall(otype T) stack(T) ?=?( stack(T)* s, stack(T) t) {22 if ( s ->head == t.head ) return *s;23 clear( s);28 forall(otype T) stack(T) ?=?( stack(T) & s, stack(T) t ) { 29 if ( s.head == t.head ) return s; 30 clear( s ); 24 31 s{ t }; 25 return *s;32 return s; 26 33 } 27 34 28 forall(otype T) void ^?{}( stack(T)* s) { clear(s); }35 forall(otype T) void ^?{}( stack(T) & s) { clear( s ); } 29 36 30 forall(otype T) _Bool empty( const stack(T)* s) { return s->head == 0; }37 forall(otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; } 31 38 32 forall(otype T) void push(stack(T)* s, T value) { 33 s->head = ((stack_node(T)*)malloc()){ value, s->head }; /***/ 39 forall(otype T) void push( stack(T) & s, T value ) { 40 // s.head = new( value, s.head ); 41 stack_node(T)* new_node = ((stack_node(T)*)malloc()); 42 (*new_node){ value, s.head }; /***/ 43 s.head = new_node; 34 44 } 35 45 36 forall(otype T) T pop(stack(T)* s) { 37 stack_node(T)* n = s->head; 38 s->head = n->next; 39 T x = n->value; 40 ^n{}; 41 free(n); 42 return x; 46 forall(otype T) T pop( stack(T) & s ) { 47 stack_node(T) * n = s.head; 48 s.head = n->next; 49 T v = n->value; 50 delete( n ); 51 return v; 43 52 } 44 53 45 forall(otype T) void clear( stack(T)* s) {46 for ( stack_node(T)* next = s->head; next; ) {47 stack_node(T) * crnt = next;54 forall(otype T) void clear( stack(T) & s ) { 55 for ( stack_node(T) * next = s.head; next; ) { 56 stack_node(T) * crnt = next; 48 57 next = crnt->next; 49 delete( crnt);58 delete( crnt ); 50 59 } 51 s ->head = 0;60 s.head = 0; 52 61 } -
doc/papers/general/evaluation/cfa-stack.h
r094476d rcaa649b 3 3 forall(otype T) struct stack_node; 4 4 forall(otype T) struct stack { 5 stack_node(T) * head;5 stack_node(T) * head; 6 6 }; 7 7 8 forall(otype T) void ?{}( stack(T)* s);9 forall(otype T) void ?{}( stack(T)* s, stack(T) t);10 forall(otype T) stack(T) ?=?( stack(T)* s, stack(T) t);11 forall(otype T) void ^?{}( stack(T)*s);8 forall(otype T) void ?{}( stack(T) & s ); 9 forall(otype T) void ?{}( stack(T) & s, stack(T) t ); 10 forall(otype T) stack(T) ?=?( stack(T) & s, stack(T) t ); 11 forall(otype T) void ^?{}( stack(T) & s); 12 12 13 forall(otype T) _Bool empty( const stack(T)* s);14 forall(otype T) void push( stack(T)* s, T value);15 forall(otype T) T pop( stack(T)* s);16 forall(otype T) void clear( stack(T)* s);13 forall(otype T) _Bool empty( const stack(T) & s ); 14 forall(otype T) void push( stack(T) & s, T value ); 15 forall(otype T) T pop( stack(T) & s ); 16 forall(otype T) void clear( stack(T) & s );
Note:
See TracChangeset
for help on using the changeset viewer.