Changes in doc/papers/general/Paper.tex [48b9b36:c8ad5d9]
- File:
-
- 1 edited
-
doc/papers/general/Paper.tex (modified) (96 diffs)
Legend:
- Unmodified
- Added
- Removed
-
doc/papers/general/Paper.tex
r48b9b36 rc8ad5d9 54 54 \newcommand{\TODO}[1]{} % TODO elided 55 55 56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%57 58 56 % Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore 59 57 % removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR … … 62 60 \renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}} 63 61 64 \renewcommand*{\thefootnote}{\Alph{footnote}} % hack because fnsymbol does not work65 %\renewcommand*{\thefootnote}{\fnsymbol{footnote}}66 67 62 \makeatletter 68 63 % parindent is relative, i.e., toggled on/off in environments like itemize, so store the value for … … 79 74 \setlength{\gcolumnposn}{3.5in} 80 75 \setlength{\columnposn}{\gcolumnposn} 81 82 76 \newcommand{\C}[2][\@empty]{\ifx#1\@empty\else\global\setlength{\columnposn}{#1}\global\columnposn=\columnposn\fi\hfill\makebox[\textwidth-\columnposn][l]{\lst@basicstyle{\LstCommentStyle{#2}}}} 83 77 \newcommand{\CRT}{\global\columnposn=\gcolumnposn} … … 165 159 literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1 166 160 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1 167 {<}{\textrm{\textless}}1 {>}{\textrm{\textgreater}}1 168 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.5ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex{\textrm{\textgreater}}}2, 161 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex{\textgreater}}2, 169 162 moredelim=**[is][\color{red}]{`}{`}, 170 163 }% lstset … … 180 173 \lstMakeShortInline@% 181 174 182 \let\OLDthebibliography\thebibliography183 \renewcommand\thebibliography[1]{184 \OLDthebibliography{#1}185 \setlength{\parskip}{0pt}186 \setlength{\itemsep}{4pt plus 0.3ex}187 }188 175 189 176 \title{\texorpdfstring{\protect\CFA : Adding Modern Programming Language Features to C}{Cforall : Adding Modern Programming Language Features to C}} … … 203 190 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. 204 191 This installation base and the programmers producing it represent a massive software-engineering investment spanning decades and likely to continue for decades more. 205 Nevertheless, C, first standardized almost forty years ago, lacks many features that make programming in more modern languages safer and more productive. 206 207 The goal of the \CFA project (pronounced ``C-for-all'') is to create an extension of C that provides modern safety and productivity features while still ensuring strong backwards compatibility with C and its programmers. 208 Prior projects have attempted similar goals but failed to honour C programming-style; 209 for instance, adding object-oriented or functional programming with garbage collection is a non-starter for many C developers. 192 Nevertheless, C, first standardized over thirty years ago, lacks many features that make programming in more modern languages safer and more productive. 193 194 The goal of the \CFA project is to create an extension of C that provides modern safety and productivity features while still ensuring strong backwards compatibility with C and its programmers. 195 Prior projects have attempted similar goals but failed to honour C programming-style; for instance, adding object-oriented or functional programming with garbage collection is a non-starter for many C developers. 210 196 Specifically, \CFA is designed to have an orthogonal feature-set based closely on the C programming paradigm, so that \CFA features can be added \emph{incrementally} to existing C code-bases, and C programmers can learn \CFA extensions on an as-needed basis, preserving investment in existing code and programmers. 211 197 This paper presents a quick tour of \CFA features showing how their design avoids shortcomings of similar features in C and other C-like languages. … … 241 227 Love it or hate it, C is extremely popular, highly used, and one of the few systems languages. 242 228 In many cases, \CC is often used solely as a better C. 243 Nevertheless, C, first standardized almost forty years ago~\cite{ANSI89:C}, lacks many features that make programming in more modern languages safer and more productive.244 245 \CFA (pronounced ``C-for-all'', and written \CFA or Cforall) is an evolutionary extension of the C programming language that a dds modern language-features to C, while maintaining both source and runtime compatibility with C and a familiar programming model for programmers.229 Nevertheless, C, first standardized over thirty years ago, lacks many features that make programming in more modern languages safer and more productive. 230 231 \CFA (pronounced ``C-for-all'', and written \CFA or Cforall) is an evolutionary extension of the C programming language that aims to add modern language features to C, while maintaining both source and runtime compatibility with C and a familiar programming model for programmers. 246 232 The four key design goals for \CFA~\cite{Bilson03} are: 247 233 (1) The behaviour of standard C code must remain the same when translated by a \CFA compiler as when translated by a C compiler; … … 252 238 \CC is used similarly, but has the disadvantages of multiple legacy design-choices that cannot be updated and active divergence of the language model from C, requiring significant effort and training to incrementally add \CC to a C-based project. 253 239 254 All languages features discussed in this paper are working, except some advanced exception-handling features. 255 Not discussed in this paper are the integrated concurrency-constructs and user-level threading-library~\cite{Delisle18}. 256 \CFA is an \emph{open-source} project 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). 240 \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). 257 241 Ultimately, a compiler is necessary for advanced features and optimal performance. 258 % @plg2[9]% cd cfa-cc/src; cloc ArgTweak CodeGen CodeTools Common Concurrency ControlStruct Designators GenPoly InitTweak MakeLibCfa.cc MakeLibCfa.h Parser ResolvExpr SymTab SynTree Tuples driver prelude main.cc 259 % ------------------------------------------------------------------------------- 260 % Language files blank comment code 261 % ------------------------------------------------------------------------------- 262 % C++ 108 5420 5232 34961 263 % C/C++ Header 86 2379 2450 8464 264 % Teamcenter def 2 115 65 1387 265 % make 5 168 87 1052 266 % C 20 109 403 488 267 % awk 1 12 26 121 268 % sed 1 0 0 6 269 % ------------------------------------------------------------------------------- 270 % SUM: 223 8203 8263 46479 271 % ------------------------------------------------------------------------------- 272 The \CFA translator is 200+ files and 46,000+ lines of code written in C/\CC. 273 Starting with a translator versus a compiler makes it easier and faster to generate and debug C object-code rather than intermediate, assembler or machine code. 274 The translator design is based on the \emph{visitor pattern}, allowing multiple passes over the abstract code-tree, which works well for incrementally adding new feature through additional visitor passes. 275 At the heart of the translator is the type resolver, which handles the polymorphic routine/type overload-resolution. 276 % @plg2[8]% cd cfa-cc/src; cloc libcfa 277 % ------------------------------------------------------------------------------- 278 % Language files blank comment code 279 % ------------------------------------------------------------------------------- 280 % C 35 1256 1240 9116 281 % C/C++ Header 54 358 1106 1198 282 % make 2 201 325 1167 283 % C++ 3 18 17 124 284 % Assembly 3 56 97 111 285 % Bourne Shell 2 2 0 25 286 % awk 1 4 0 22 287 % ------------------------------------------------------------------------------- 288 % SUM: 100 1895 2785 11763 289 % ------------------------------------------------------------------------------- 290 The \CFA runtime system is 100+ files and 11,000+ lines of code, written in \CFA. 291 Currently, the \CFA runtime is the largest \emph{user} of \CFA providing a vehicle to test the language features and implementation. 292 % @plg2[6]% cd cfa-cc/src; cloc tests examples benchmark 293 % ------------------------------------------------------------------------------- 294 % Language files blank comment code 295 % ------------------------------------------------------------------------------- 296 % C 237 12260 2869 23286 297 % make 8 464 245 2838 298 % C/C++ Header 22 225 175 785 299 % Python 5 131 93 420 300 % C++ 10 48 5 201 301 % Lua 2 31 4 126 302 % Java 4 5 0 80 303 % Go 2 11 9 40 304 % ------------------------------------------------------------------------------- 305 % SUM: 290 13175 3400 27776 306 % ------------------------------------------------------------------------------- 307 The \CFA tests are 290+ files and 27,000+ lines of code. 308 The tests illustrate syntactic and semantic features in \CFA, plus a growing number of runtime benchmarks. 309 The tests check for correctness and are used for daily regression testing of 3800+ commits. 242 All features discussed in this paper are working, unless otherwise stated as under construction. 310 243 311 244 Finally, it is impossible to describe a programming language without usages before definitions. … … 328 261 There are only two hard things in Computer Science: cache invalidation and \emph{naming things} -- Phil Karlton 329 262 \end{quote} 330 \vspace{-9pt}331 263 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. 332 264 \CFA extends the built-in operator overloading by allowing users to define overloads for any function, not just operators, and even any variable; … … 334 266 Code generation for these overloaded functions and variables is implemented by the usual approach of mangling the identifier names to include a representation of their type, while \CFA decides which overload to apply based on the same ``usual arithmetic conversions'' used in C to disambiguate operator overloads. 335 267 As an example: 336 \begin{cfa} 337 int max = 2147483647; $\C[4in]{// (1)}$ 338 double max = 1.7976931348623157E+308; $\C{// (2)}$ 268 269 \begin{cfa} 270 int max = 2147483647; $\C[4in]{// (1)}$ 271 double max = 1.7976931348623157E+308; $\C{// (2)}$ 339 272 int max( int a, int b ) { return a < b ? b : a; } $\C{// (3)}$ 340 273 double max( double a, double b ) { return a < b ? b : a; } $\C{// (4)}\CRT$ 341 max( 7, -max ); $\C {// uses (3) and (1), by matching int from constant 7}$274 max( 7, -max ); $\C[2.75in]{// uses (3) and (1), by matching int from constant 7}$ 342 275 max( max, 3.14 ); $\C{// uses (4) and (2), by matching double from constant 3.14}$ 343 max( max, -max ); $\C{// ERROR ,ambiguous}$344 int m = max( max, -max ); $\C{// uses (3) and (1) twice, by matching return type} $276 max( max, -max ); $\C{// ERROR: ambiguous}$ 277 int m = max( max, -max ); $\C{// uses (3) and (1) twice, by matching return type}\CRT$ 345 278 \end{cfa} 346 279 … … 351 284 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. 352 285 353 \Celeven added @_Generic@ expressions ~\cite[\S~6.5.1.1]{C11}, which is used with preprocessor macros to providead-hoc polymorphism;286 \Celeven added @_Generic@ expressions, which is used in preprocessor macros to provide a form of ad-hoc polymorphism; 354 287 however, this polymorphism is both functionally and ergonomically inferior to \CFA name overloading. 355 288 The macro wrapping the generic expression imposes some limitations; 356 289 \eg, it cannot implement the example above, because the variables @max@ are ambiguous with the functions @max@. 357 290 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 dispatch functions, which must all have distinct names. 358 \CFA supports @_Generic@ expressions for backwards compatibility, but it is an unnecessary mechanism. \TODO{actually implement that}291 For backwards compatibility, \CFA supports @_Generic@ expressions, but it is an unnecessary mechanism. \TODO{actually implement that} 359 292 360 293 % http://fanf.livejournal.com/144696.html … … 384 317 \begin{cfa} 385 318 forall( otype T `| { T ?+?(T, T); }` ) T twice( T x ) { return x `+` x; } $\C{// ? denotes operands}$ 386 int val = twice( twice( 3.7 ) ); $\C{// val == 14}$319 int val = twice( twice( 3.7 ) ); 387 320 \end{cfa} 388 321 which works for any type @T@ with a matching addition operator. 389 322 The polymorphism is achieved by creating a wrapper function for calling @+@ with @T@ bound to @double@, then passing this function to the first call of @twice@. 390 323 There is now the option of using the same @twice@ and converting the result to @int@ on assignment, or creating another @twice@ with type parameter @T@ bound to @int@ because \CFA uses the return type~\cite{Cormack81,Baker82,Ada} in its type analysis. 391 The first approach has a late conversion from @double@ to @int@ on the final assignment, while the second has an ea rlyconversion to @int@.324 The first approach has a late conversion from @double@ to @int@ on the final assignment, while the second has an eager conversion to @int@. 392 325 \CFA minimizes the number of conversions and their potential to lose information, so it selects the first approach, which corresponds with C-programmer intuition. 393 326 … … 396 329 A simple example is leveraging the existing type-unsafe (@void *@) C @bsearch@ to binary search a sorted float array: 397 330 \begin{cfa} 398 void * bsearch( const void * key, const void * base, size_t nmemb, size_t size, 399 int (* compar)( const void *, const void * )); 331 void * bsearch( const void * key, const void * base, size_t nmemb, size_t size, int (* compar)( const void *, const void * )); 400 332 int comp( const void * t1, const void * t2 ) { 401 333 return *(double *)t1 < *(double *)t2 ? -1 : *(double *)t2 < *(double *)t1 ? 1 : 0; … … 423 355 424 356 \CFA has replacement libraries condensing hundreds of existing C functions into tens of \CFA overloaded functions, all without rewriting the actual computations (see Section~\ref{sec:libraries}). 425 For example, it is possible to write a type-safe \CFA wrapper @malloc@ based on the C @malloc@ , where the return type supplies the type/size of the allocation, which is impossible in most type systems.357 For example, it is possible to write a type-safe \CFA wrapper @malloc@ based on the C @malloc@: 426 358 \begin{cfa} 427 359 forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); } 428 // select type and size from left-hand side 429 int * ip = malloc(); double * dp = malloc(); struct S {...} * sp = malloc(); 430 \end{cfa} 360 int * ip = malloc(); $\C{// select type and size from left-hand side}$ 361 double * dp = malloc(); 362 struct S {...} * sp = malloc(); 363 \end{cfa} 364 where the return type supplies the type/size of the allocation, which is impossible in most type systems. 431 365 432 366 Call-site inferencing and nested functions provide a localized form of inheritance. … … 435 369 \begin{cfa} 436 370 forall( otype T | { int ?<?( T, T ); } ) void qsort( const T * arr, size_t size ) { /* use C qsort */ } 437 int main(){371 { 438 372 int ?<?( double x, double y ) { return x `>` y; } $\C{// locally override behaviour}$ 439 qsort( vals, 10 );$\C{// descending sort}$440 } 441 \end{cfa} 442 The local version of @?<?@ performs @?>?@ overridingthe built-in @?<?@ so it is passed to @qsort@.373 qsort( vals, size ); $\C{// descending sort}$ 374 } 375 \end{cfa} 376 Within the block, the nested version of @?<?@ performs @?>?@ and this local version overrides the built-in @?<?@ so it is passed to @qsort@. 443 377 Hence, programmers can easily form local environments, adding and modifying appropriate functions, to maximize reuse of other existing functions and types. 444 378 445 To reduce duplication, it is possible to distribute a group of @forall@ (and storage-class qualifiers) over functions/types, so each block declaration is prefixed by the group (see example in Appendix~\ref{s:CforallStack}). 446 \begin{cfa} 447 forall( otype `T` ) { $\C{// distribution block, add forall qualifier to declarations}$379 Under construction is a mechanism to distribute @forall@ over routines/types, where each block declaration is prefixed with the initial @forall@ clause significantly reducing duplication (see @stack@ examples in Section~\ref{sec:eval}): 380 \begin{cfa} 381 forall( otype `T` ) { $\C{// forall block}$ 448 382 struct stack { stack_node(`T`) * head; }; $\C{// generic type}$ 449 inline { $\C{// nested distribution block, add forall/inline to declarations}$ 450 void push( stack(`T`) & s, `T` value ) ... $\C{// generic operations}$ 451 } 452 } 453 \end{cfa} 454 455 456 \vspace*{-2pt} 383 void push( stack(`T`) & s, `T` value ) ... $\C{// generic operations}$ 384 T pop( stack(`T`) & s ) ... 385 } 386 \end{cfa} 387 388 457 389 \subsection{Traits} 458 390 459 391 \CFA provides \newterm{traits} to name a group of type assertions, where the trait name allows specifying the same set of assertions in multiple locations, preventing repetition mistakes at each function declaration: 460 461 \begin{cquote} 462 \lstDeleteShortInline@% 463 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}} 464 \begin{cfa} 465 trait `sumable`( otype T ) { 466 void `?{}`( T &, zero_t ); // 0 literal constructor 467 T ?+?( T, T ); // assortment of additions 468 T `?+=?`( T &, T ); 469 T ++?( T & ); 470 T ?++( T & ); 392 \begin{cfa} 393 trait `summable`( otype T ) { 394 void ?{}( T *, zero_t ); $\C{// constructor from 0 literal}$ 395 T ?+?( T, T ); $\C{// assortment of additions}$ 396 T ?+=?( T *, T ); 397 T ++?( T * ); 398 T ?++( T * ); 471 399 }; 472 \end{cfa} 473 & 474 \begin{cfa} 475 forall( otype T `| sumable( T )` ) // use trait 476 T sum( T a[$\,$], size_t size ) { 477 `T` total = { `0` }; // initialize by 0 constructor 478 for ( size_t i = 0; i < size; i += 1 ) 479 total `+=` a[i]; // select appropriate + 400 forall( otype T `| summable( T )` ) T sum( T a[$\,$], size_t size ) {$\C{// use trait}$ 401 `T` total = { `0` }; $\C{// instantiate T from 0 by calling its constructor}$ 402 for ( unsigned int i = 0; i < size; i += 1 ) total `+=` a[i]; $\C{// select appropriate +}$ 480 403 return total; 481 404 } 482 405 \end{cfa} 483 \end{tabular} 484 \lstMakeShortInline@% 485 \end{cquote} 486 487 Note, the @sumable@ trait does not include a copy constructor needed for the right side of @?+=?@ and return; 488 it is provided by @otype@, which is syntactic sugar for the following trait: 406 407 In fact, the set of @summable@ trait operators is incomplete, as it is missing assignment for type @T@, but @otype@ is syntactic sugar for the following implicit trait: 489 408 \begin{cfa} 490 409 trait otype( dtype T | sized(T) ) { // sized is a pseudo-trait for types with known size and alignment … … 504 423 Instead, each polymorphic function (or generic type) defines the structural type needed for its execution (polymorphic type-key), and this key is fulfilled at each call site from the lexical environment, which is similar to Go~\cite{Go} interfaces. 505 424 Hence, new lexical scopes and nested functions are used extensively to create local subtypes, as in the @qsort@ example, without having to manage a nominal-inheritance hierarchy. 506 %(Nominal inheritance can be approximated with traits using marker variables or functions, as is done in Go.)425 (Nominal inheritance can be approximated with traits using marker variables or functions, as is done in Go.) 507 426 508 427 % Nominal inheritance can be simulated with traits using marker variables or functions: … … 543 462 544 463 \CC, Java, and other languages use \newterm{generic types} to produce type-safe abstract data-types. 545 \CFA generic typesintegrate efficiently and naturally with the existing polymorphic functions, while retaining backwards compatibility with C and providing separate compilation.464 \CFA also implements generic types that integrate efficiently and naturally with the existing polymorphic functions, while retaining backwards compatibility with C and providing separate compilation. 546 465 However, for known concrete parameters, the generic-type definition can be inlined, like \CC templates. 547 466 548 467 A generic type can be declared by placing a @forall@ specifier on a @struct@ or @union@ declaration, and instantiated using a parenthesized list of types after the type name: 549 \begin{cquote} 550 \lstDeleteShortInline@% 551 \begin{tabular}{@{}l|@{\hspace{\parindentlnth}}l@{}} 552 \begin{cfa} 553 `forall( otype R, otype S )` struct pair { 554 R first; S second; 468 \begin{cfa} 469 forall( otype R, otype S ) struct pair { 470 R first; 471 S second; 555 472 }; 556 `forall( otype T )` // dynamic 557 T value( pair(const char *, T) p ) { return p.second; } 558 `forall( dtype F, otype T )` // dtype-static (concrete) 559 T value( pair(F *, T * ) p) { return *p.second; } 560 \end{cfa} 561 & 562 \begin{cfa} 563 pair(const char *, int) p = {"magic", 42}; // concrete 473 forall( otype T ) T value( pair( const char *, T ) p ) { return p.second; } $\C{// dynamic}$ 474 forall( dtype F, otype T ) T value( pair( F *, T * ) p ) { return *p.second; } $\C{// dtype-static (concrete)}$ 475 476 pair( const char *, int ) p = { "magic", 42 }; $\C{// concrete}$ 564 477 int i = value( p ); 565 pair( void *, int *) q = { 0, &p.second }; // concrete478 pair( void *, int * ) q = { 0, &p.second }; $\C{// concrete}$ 566 479 i = value( q ); 567 480 double d = 1.0; 568 pair( double *, double *) r = { &d, &d }; // concrete481 pair( double *, double * ) r = { &d, &d }; $\C{// concrete}$ 569 482 d = value( r ); 570 483 \end{cfa} 571 \end{tabular}572 \lstMakeShortInline@%573 \end{cquote}574 484 575 485 \CFA classifies generic types as either \newterm{concrete} or \newterm{dynamic}. 576 486 Concrete types have a fixed memory layout regardless of type parameters, while dynamic types vary in memory layout depending on their type parameters. 577 487 A \newterm{dtype-static} type has polymorphic parameters but is still concrete. 578 Polymorphic pointers are an example of dtype-static types; 579 given some type variable @T@, @T@ is a polymorphic type, as is @T *@, but @T *@ has a fixed size and can therefore be represented by @void *@ in code generation. 488 Polymorphic pointers are an example of dtype-static types, \eg @forall(dtype T) T *@ is a polymorphic type, but for any @T@, @T *@ is a fixed-sized pointer, and therefore, can be represented by a @void *@ in code generation. 580 489 581 490 \CFA generic types also allow checked argument-constraints. … … 594 503 \begin{cfa} 595 504 struct _pair_conc0 { 596 const char * first; int second; 505 const char * first; 506 int second; 597 507 }; 598 508 \end{cfa} … … 602 512 \begin{cfa} 603 513 struct _pair_conc1 { 604 void * first, * second; 514 void * first; 515 void * second; 605 516 }; 606 517 \end{cfa} … … 657 568 Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \newterm{tag-structures}. 658 569 Sometimes information is only used for type-checking and can be omitted at runtime, \eg: 659 \begin{cquote}660 \lstDeleteShortInline@%661 \begin{tabular}{@{}l|@{\hspace{\parindentlnth}}l@{}}662 570 \begin{cfa} 663 571 forall( dtype Unit ) struct scalar { unsigned long value; }; 664 572 struct metres {}; 665 573 struct litres {}; 574 666 575 forall( dtype U ) scalar(U) ?+?( scalar(U) a, scalar(U) b ) { 667 576 return (scalar(U)){ a.value + b.value }; 668 577 } 669 \end{cfa} 670 & 671 \begin{cfa} 672 scalar(metres) half_marathon = { 21_098 }; 673 scalar(litres) pool = { 2_500_000 }; 674 scalar(metres) marathon = half_marathon + 675 half_marathon; 676 scalar(litres) two_pools = pool + pool; 677 `marathon + pool;` // ERROR, mismatched types 678 \end{cfa} 679 \end{tabular} 680 \lstMakeShortInline@% 681 \end{cquote} 578 scalar(metres) half_marathon = { 21_093 }; 579 scalar(litres) swimming_pool = { 2_500_000 }; 580 scalar(metres) marathon = half_marathon + half_marathon; 581 scalar(litres) two_pools = swimming_pool + swimming_pool; 582 marathon + swimming_pool; $\C{// compilation ERROR}$ 583 \end{cfa} 682 584 @scalar@ is a dtype-static type, so all uses have a single structure definition, containing @unsigned long@, and can share the same implementations of common functions like @?+?@. 683 585 These implementations may even be separately compiled, unlike \CC template functions. … … 961 863 } 962 864 \end{cfa} 963 One more step permits the summation of any sum able type with all arguments of the same type:964 \begin{cfa} 965 trait sum able( otype T ) {865 One more step permits the summation of any summable type with all arguments of the same type: 866 \begin{cfa} 867 trait summable( otype T ) { 966 868 T ?+?( T, T ); 967 869 }; 968 forall( otype R | sum able( R ) ) R sum( R x, R y ) {870 forall( otype R | summable( R ) ) R sum( R x, R y ) { 969 871 return x + y; 970 872 } 971 forall( otype R, ttype Params | sum able(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) {873 forall( otype R, ttype Params | summable(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) { 972 874 return sum( x + y, rest ); 973 875 } … … 1020 922 \begin{cfa} 1021 923 forall( dtype T0, dtype T1 | sized(T0) | sized(T1) ) struct _tuple2 { 1022 T0 field_0; T1 field_1; $\C{// generated before the first 2-tuple}$ 924 T0 field_0; $\C{// generated before the first 2-tuple}$ 925 T1 field_1; 1023 926 }; 1024 927 _tuple2(int, int) f() { 1025 928 _tuple2(double, double) x; 1026 929 forall( dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2) ) struct _tuple3 { 1027 T0 field_0; T1 field_1; T2 field_2; $\C{// generated before the first 3-tuple}$ 930 T0 field_0; $\C{// generated before the first 3-tuple}$ 931 T1 field_1; 932 T2 field_2; 1028 933 }; 1029 934 _tuple3(int, double, int) y; 1030 935 } 1031 936 \end{cfa} 1032 Tuple expressions are then converted directly into compound literals, \eg @[5, 'x', 1.24]@ becomes @(_tuple3(int, char,@ @double)){ 5, 'x', 1.24 }@. 937 {\sloppy 938 Tuple expressions are then simply converted directly into compound literals, \eg @[5, 'x', 1.24]@ becomes @(_tuple3(int, char, double)){ 5, 'x', 1.24 }@. 939 \par}% 1033 940 1034 941 \begin{comment} … … 1115 1022 \lstDeleteShortInline@% 1116 1023 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1117 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\1024 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1118 1025 \begin{cfa} 1119 1026 case 2, 10, 34, 42: … … 1130 1037 \lstDeleteShortInline@% 1131 1038 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1132 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\1039 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1133 1040 \begin{cfa} 1134 1041 case 2~42: … … 1183 1090 \centering 1184 1091 \lstDeleteShortInline@% 1185 \begin{tabular}{@{}l |@{\hspace{\parindentlnth}}l@{}}1186 \multicolumn{1}{ @{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\1092 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1093 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1187 1094 \begin{cfa} 1188 1095 `choose` ( day ) { 1189 1096 case Mon~Thu: // program 1190 1097 1191 case Fri: // program1098 case Fri: // program 1192 1099 wallet += pay; 1193 1100 `fallthrough;` 1194 case Sat: // party1101 case Sat: // party 1195 1102 wallet -= party; 1196 1103 1197 1104 case Sun: // rest 1198 1105 1199 default: // printerror1106 default: // error 1200 1107 } 1201 1108 \end{cfa} … … 1205 1112 case Mon: case Tue: case Wed: case Thu: // program 1206 1113 `break;` 1207 case Fri: // program1114 case Fri: // program 1208 1115 wallet += pay; 1209 1116 1210 case Sat: // party1117 case Sat: // party 1211 1118 wallet -= party; 1212 1119 `break;` 1213 1120 case Sun: // rest 1214 1121 `break;` 1215 default: // printerror1122 default: // error 1216 1123 } 1217 1124 \end{cfa} … … 1229 1136 \centering 1230 1137 \lstDeleteShortInline@% 1231 \begin{tabular}{@{}l |@{\hspace{\parindentlnth}}l@{}}1232 \multicolumn{1}{ @{}c|@{\hspace{\parindentlnth}}}{\textbf{non-terminator}} & \multicolumn{1}{c@{}}{\textbf{target label}} \\1138 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1139 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{non-terminator}} & \multicolumn{1}{c}{\textbf{target label}} \\ 1233 1140 \begin{cfa} 1234 1141 choose ( ... ) { … … 1273 1180 \begin{figure} 1274 1181 \lstDeleteShortInline@% 1275 \begin{tabular}{@{\hspace{\parindentlnth}}l |@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}}1276 \multicolumn{1}{@{\hspace{\parindentlnth}}c |@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}} \\1182 \begin{tabular}{@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}} 1183 \multicolumn{1}{@{\hspace{\parindentlnth}}c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}} \\ 1277 1184 \begin{cfa} 1278 1185 `LC:` { … … 1282 1189 `LIF:` if ( ... ) { 1283 1190 `LF:` for ( ... ) { 1284 ... break `LC`; ... 1285 ... break `LS`; ... 1286 ... break `LIF`; ... 1287 ... continue `LF;` ... 1288 ... break `LF`; ... 1191 `LW:` while ( ... ) { 1192 ... break `LC`; ... 1193 ... break `LS`; ... 1194 ... break `LIF`; ... 1195 ... continue `LF;` ... 1196 ... break `LF`; ... 1197 ... continue `LW`; ... 1198 ... break `LW`; ... 1199 } // while 1289 1200 } // for 1290 1201 } else { … … 1302 1213 if ( ... ) { 1303 1214 for ( ... ) { 1304 ... goto `LC`; ... 1305 ... goto `LS`; ... 1306 ... goto `LIF`; ... 1307 ... goto `LFC`; ... 1308 ... goto `LFB`; ... 1215 while ( ... ) { 1216 ... goto `LC`; ... 1217 ... goto `LS`; ... 1218 ... goto `LIF`; ... 1219 ... goto `LFC`; ... 1220 ... goto `LFB`; ... 1221 ... goto `LWC`; ... 1222 ... goto `LWB`; ... 1223 `LWC`: ; } `LWB:` ; 1309 1224 `LFC:` ; } `LFB:` ; 1310 1225 } else { … … 1328 1243 // continue loop 1329 1244 // terminate loop 1245 // continue loop 1246 // terminate loop 1330 1247 1331 1248 1332 1249 1333 1250 // terminate if 1251 1252 1334 1253 1335 1254 \end{cfa} … … 1358 1277 \subsection{Exception Handling} 1359 1278 1360 The following framework for \CFA exception -handling is in place, excluding some runtime type-information and virtual functions.1279 The following framework for \CFA exception handling is in place, excluding some runtime type-information and virtual functions. 1361 1280 \CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling})~\cite{Buhr92b,Buhr00a}. 1362 1281 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. … … 1369 1288 \begin{cquote} 1370 1289 \lstDeleteShortInline@% 1371 \begin{tabular}{@{}l |@{\hspace{\parindentlnth}}l@{}}1372 \multicolumn{1}{ @{}c|@{\hspace{\parindentlnth}}}{\textbf{Resumption}} & \multicolumn{1}{c@{}}{\textbf{Termination}} \\1290 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1291 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{Resumption}} & \multicolumn{1}{c}{\textbf{Termination}} \\ 1373 1292 \begin{cfa} 1374 1293 `exception R { int fix; };` … … 1436 1355 resume( $\emph{alternate-stack}$ ) 1437 1356 \end{cfa} 1438 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task ~\cite{Delisle18}.1357 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task\footnote{\CFA coroutine and concurrency features are discussed in a separately submitted paper.}~\cite{Delisle18}. 1439 1358 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 handler returns. 1440 1359 … … 1486 1405 If an exception is raised and caught, the handler is run before the finally clause. 1487 1406 Like a destructor (see Section~\ref{s:ConstructorsDestructors}), a finally clause can raise an exception but not if there is an exception being propagated. 1488 Mimicking the @finally@ clause with mechanisms like RAII is non-trivial when there are multiple types and local accesses.1407 Mimicking the @finally@ clause with mechanisms like RAII is non-trivially when there are multiple types and local accesses. 1489 1408 1490 1409 … … 1492 1411 \label{s:WithStatement} 1493 1412 1494 Heterogeneous data is often aggregated into a structure/union. 1495 To reduce syntactic noise, \CFA provides a @with@ statement (see Pascal~\cite[\S~4.F]{Pascal}) to elide aggregate field-qualification by opening a scope containing the field identifiers. 1496 \begin{cquote} 1497 \vspace*{-\baselineskip}%??? 1498 \lstDeleteShortInline@% 1499 \begin{cfa} 1500 struct S { char c; int i; double d; }; 1413 Grouping heterogeneous data into \newterm{aggregate}s (structure/union) is a common programming practice, and an aggregate can be further organized into more complex structures, such as arrays and containers: 1414 \begin{cfa} 1415 struct S { $\C{// aggregate}$ 1416 char c; $\C{// fields}$ 1417 int i; 1418 double d; 1419 }; 1420 S s, as[10]; 1421 \end{cfa} 1422 However, functions manipulating aggregates must repeat the aggregate name to access its containing fields: 1423 \begin{cfa} 1424 void f( S s ) { 1425 `s.`c; `s.`i; `s.`d; $\C{// access containing fields}$ 1426 } 1427 \end{cfa} 1428 which extends to multiple levels of qualification for nested aggregates. 1429 A similar situation occurs in object-oriented programming, \eg \CC: 1430 \begin{C++} 1431 struct S { 1432 char c; $\C{// fields}$ 1433 int i; 1434 double d; 1435 void f() { $\C{// implicit ``this'' aggregate}$ 1436 `this->`c; `this->`i; `this->`d; $\C{// access containing fields}$ 1437 } 1438 } 1439 \end{C++} 1440 Object-oriented nesting of member functions in a \lstinline[language=C++]@class/struct@ allows eliding \lstinline[language=C++]@this->@ because of lexical scoping. 1441 However, for other aggregate parameters, qualification is necessary: 1442 \begin{cfa} 1501 1443 struct T { double m, n; }; 1502 // multiple aggregate parameters 1503 \end{cfa} 1504 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}} 1505 \begin{cfa}1506 void f( S & s, T & t ) { 1507 `s.`c; `s.`i; `s.`d; 1508 `t.`m; `t.`n; 1509 } 1510 \ end{cfa}1511 & 1512 \begin{cfa} 1513 void f( S & s, T & t ) `with ( s, t )` { 1514 c; i; d; // no qualification 1515 m; n; 1516 }1517 \end{cfa} 1518 \end{tabular} 1519 \lstMakeShortInline@% 1520 \end{cquote}1521 Object-oriented programming languages only provide implicit qualification for the receiver. 1444 int S::f( T & t ) { $\C{// multiple aggregate parameters}$ 1445 c; i; d; $\C{\color{red}// this--{\textgreater}.c, this--{\textgreater}.i, this--{\textgreater}.d}$ 1446 `t.`m; `t.`n; $\C{// must qualify}$ 1447 } 1448 \end{cfa} 1449 1450 To simplify the programmer experience, \CFA provides a @with@ statement (see Pascal~\cite[\S~4.F]{Pascal}) to elide aggregate qualification to fields by opening a scope containing the field identifiers. 1451 Hence, the qualified fields become variables with the side-effect that it is easier to optimizing field references in a block. 1452 \begin{cfa} 1453 void f( S & this ) `with ( this )` { $\C{// with statement}$ 1454 c; i; d; $\C{\color{red}// this.c, this.i, this.d}$ 1455 } 1456 \end{cfa} 1457 with the generality of opening multiple aggregate-parameters: 1458 \begin{cfa} 1459 void f( S & s, T & t ) `with ( s, t )` { $\C{// multiple aggregate parameters}$ 1460 c; i; d; $\C{\color{red}// s.c, s.i, s.d}$ 1461 m; n; $\C{\color{red}// t.m, t.n}$ 1462 } 1463 \end{cfa} 1522 1464 1523 1465 In detail, the @with@ statement has the form: … … 1532 1474 The object is the implicit qualifier for the open structure-fields. 1533 1475 1534 All expressions in the expression list are open in parallel within the compound statement, which is different from Pascal, which nests the openings from left to right. 1476 All expressions in the expression list are open in parallel within the compound statement. 1477 This semantic is different from Pascal, which nests the openings from left to right. 1535 1478 The difference between parallel and nesting occurs for fields with the same name and type: 1536 1479 \begin{cfa} … … 1539 1482 with ( s, t ) { 1540 1483 j + k; $\C{// unambiguous, s.j + t.k}$ 1541 m = 5.0; $\C{// unambiguous, s.m = 5.0}$1542 m = 1; $\C{// unambiguous, t.m = 1}$1543 int a = m; $\C{// unambiguous, a = t.m}$1544 double b = m; $\C{// unambiguous, b = s.m}$1484 m = 5.0; $\C{// unambiguous, t.m = 5.0}$ 1485 m = 1; $\C{// unambiguous, s.m = 1}$ 1486 int a = m; $\C{// unambiguous, a = s.i }$ 1487 double b = m; $\C{// unambiguous, b = t.m}$ 1545 1488 int c = s.i + t.i; $\C{// unambiguous, qualification}$ 1546 (double)m; $\C{// unambiguous, cast s.m}$1489 (double)m; $\C{// unambiguous, cast}$ 1547 1490 } 1548 1491 \end{cfa} … … 1568 1511 and implicitly opened \emph{after} a function-body open, to give them higher priority: 1569 1512 \begin{cfa} 1570 void ?{}( S & s, int `i` ) with ( s ) ` {` `with( $\emph{\color{red}params}$ )` {1513 void ?{}( S & s, int `i` ) with ( s ) `with( $\emph{\color{red}params}$ )` { 1571 1514 s.i = `i`; j = 3; m = 5.5; 1572 } `}`1515 } 1573 1516 \end{cfa} 1574 1517 Finally, a cast may be used to disambiguate among overload variables in a @with@ expression: … … 1638 1581 \lstDeleteShortInline@% 1639 1582 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{}} 1640 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\1583 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1641 1584 \begin{cfa} 1642 1585 `[5] *` int x1; … … 1666 1609 \lstDeleteShortInline@% 1667 1610 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1668 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\1611 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1669 1612 \begin{cfa} 1670 1613 `*` int x, y; 1671 int z;1672 \end{cfa} 1673 & 1674 \begin{cfa} 1675 int `*`x, `*`y , z;1614 int y; 1615 \end{cfa} 1616 & 1617 \begin{cfa} 1618 int `*`x, `*`y; 1676 1619 1677 1620 \end{cfa} … … 1679 1622 \lstMakeShortInline@% 1680 1623 \end{cquote} 1681 % The downside of the \CFA semantics is the need to separate regular and pointer declarations. 1682 The separation of regular and pointer declarations by \CFA declarations enforces greater clarity with only slightly more syntax. 1624 The downside of the \CFA semantics is the need to separate regular and pointer declarations. 1683 1625 1684 1626 \begin{comment} … … 1687 1629 \lstDeleteShortInline@% 1688 1630 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{}} 1689 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{C}} \\1631 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{C}} \\ 1690 1632 \begin{cfa} 1691 1633 [ 5 ] int z; … … 1729 1671 \lstDeleteShortInline@% 1730 1672 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{}} 1731 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{C}} \\1673 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{C}} \\ 1732 1674 \begin{cfa} 1733 1675 extern const * const int x; … … 1754 1696 \lstDeleteShortInline@% 1755 1697 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1756 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\1698 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1757 1699 \begin{cfa} 1758 1700 y = (* int)x; … … 1782 1724 \lstDeleteShortInline@% 1783 1725 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1784 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\1726 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1785 1727 \begin{cfa} 1786 1728 [double] foo(), foo( int ), foo( double ) {...} … … 1800 1742 * [ * int ] ( int y ) gp; $\C{// pointer to function returning pointer to int with int parameter}$ 1801 1743 * [ ] ( int, char ) hp; $\C{// pointer to function returning no result with int and char parameters}$ 1802 * [ * int, int ] ( int ) jp; $\C{// pointer to function returning pointer to int and int with int parameter}\CRT$ 1803 \end{cfa} 1804 Note, the name of the function pointer is specified last, as for other variable declarations. 1744 * [ * int, int ] ( int ) jp; $\C{// pointer to function returning pointer to int and int with int parameter}$ 1745 \end{cfa} 1746 Note, a function name cannot be specified: 1747 \begin{cfa} 1748 * [ int x ] f () fp; $\C{// function name "f" is disallowed}\CRT$ 1749 \end{cfa} 1805 1750 1806 1751 Finally, new \CFA declarations may appear together with C declarations in the same program block, but cannot be mixed within a specific declaration. … … 1859 1804 This provides a much more orthogonal design for library implementors, obviating the need for workarounds such as @std::reference_wrapper@. 1860 1805 Secondly, \CFA references are rebindable, whereas \CC references have a fixed address. 1806 \newsavebox{\LstBox} 1807 \begin{lrbox}{\LstBox} 1808 \lstset{basicstyle=\footnotesize\linespread{0.9}\sf} 1809 \begin{cfa} 1810 int & r = *new( int ); 1811 ... $\C{// non-null reference}$ 1812 delete &r; $\C{// unmanaged (programmer) memory-management}$ 1813 r += 1; $\C{// undefined reference}$ 1814 \end{cfa} 1815 \end{lrbox} 1861 1816 Rebinding allows \CFA references to be default-initialized (\eg to a null pointer\footnote{ 1862 While effort has been made into non-null reference checking in \CC and Java, the exercise seems moot for any non-managed languages (C/\CC), given that it only handles one of many different error situations, \eg using a pointer after its storage is deleted.}) and point to different addresses throughout their lifetime, like pointers. 1817 While effort has been made into non-null reference checking in \CC and Java, the exercise seems moot for any non-managed languages (C/\CC), given that it only handles one of many different error situations: 1818 \begin{cquote} 1819 \usebox{\LstBox} 1820 \end{cquote} 1821 }% 1822 ) and point to different addresses throughout their lifetime, like pointers. 1863 1823 Rebinding is accomplished by extending the existing syntax and semantics of the address-of operator in C. 1864 1824 … … 1872 1832 \begin{itemize} 1873 1833 \item 1874 if @R@ is an rvalue of type {@T &@$_1 \cdots$@ &@$_r$} where $r \ge 1$ references (@&@ symbols) th en @&R@ has type {@T `*`&@$_{\color{red}2} \cdots$@ &@$_{\color{red}r}$}, \\ \ie @T@ pointer with $r-1$ references (@&@ symbols).1834 if @R@ is an rvalue of type {@T &@$_1 \cdots$@ &@$_r$} where $r \ge 1$ references (@&@ symbols) than @&R@ has type {@T `*`&@$_{\color{red}2} \cdots$@ &@$_{\color{red}r}$}, \\ \ie @T@ pointer with $r-1$ references (@&@ symbols). 1875 1835 1876 1836 \item … … 1906 1866 \end{cfa} 1907 1867 This allows complex values to be succinctly and efficiently passed to functions, without the syntactic overhead of explicit definition of a temporary variable or the runtime cost of pass-by-value. 1908 \CC allows a similar binding, but only for @const@ references; the more general semantics of \CFA are an attempt to avoid the \newterm{const poisoning} problem~\cite{Taylor10}, in which addition of a @const@ qualifier to one reference requires a cascading chain of added qualifiers.1868 \CC allows a similar binding, but only for @const@ references; the more general semantics of \CFA are an attempt to avoid the \newterm{const hell} problem, in which addition of a @const@ qualifier to one reference requires a cascading chain of added qualifiers. 1909 1869 1910 1870 … … 1920 1880 \begin{tabular}{@{}l@{\hspace{3em}}l|l@{}} 1921 1881 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{C Type Nesting}} & \multicolumn{1}{c|}{\textbf{C Implicit Hoisting}} & \multicolumn{1}{c}{\textbf{\CFA}} \\ 1882 \hline 1922 1883 \begin{cfa} 1923 1884 struct S { … … 1999 1960 The symbol \lstinline+^+ is used for the destructor name because it was the last binary operator that could be used in a unary context.}. 2000 1961 The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@. 2001 Like other \CFA operators, these names represent the syntax used to explicitly call the constructor or destructor, \eg @s{...}@ or @^s{...}@.1962 Like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @?{}(x, ...)@ or @^{}(x, ...)@. 2002 1963 The constructor and destructor have return type @void@, and the first parameter is a reference to the object type to be constructed or destructed. 2003 1964 While the first parameter is informally called the @this@ parameter, as in object-oriented languages, any variable name may be used. 2004 Both constructors and destructors allow additional paramete rs after the @this@ parameter for specifying values for initialization/de-initialization\footnote{1965 Both constructors and destructors allow additional parametes after the @this@ parameter for specifying values for initialization/de-initialization\footnote{ 2005 1966 Destruction parameters are useful for specifying storage-management actions, such as de-initialize but not deallocate.}. 2006 1967 \begin{cfa} 2007 struct VLA { int len, * data; }; $\C{// variable length array of integers}$1968 struct VLA { int len, * data; }; 2008 1969 void ?{}( VLA & vla ) with ( vla ) { len = 10; data = alloc( len ); } $\C{// default constructor}$ 2009 1970 void ^?{}( VLA & vla ) with ( vla ) { free( data ); } $\C{// destructor}$ 2010 1971 { 2011 VLA x; $\C{// implicit: \ \ x\{\};}$2012 } $\C{// implicit: \ \textasciicircum{}x\{\};}$1972 VLA x; $\C{// implicit: ?\{\}( x );}$ 1973 } $\C{// implicit: ?\^{}\{\}( x );}$ 2013 1974 \end{cfa} 2014 1975 @VLA@ is a \newterm{managed type}\footnote{ … … 2035 1996 appropriate care is taken to not recursively call the copy constructor when initializing the second parameter. 2036 1997 2037 \CFA constructors may be explicitly call ed, like Java, and destructors may be explicitly called, like \CC.1998 \CFA constructors may be explicitly call, like Java, and destructors may be explicitly called, like \CC. 2038 1999 Explicit calls to constructors double as a \CC-style \emph{placement syntax}, useful for construction of member fields in user-defined constructors and reuse of existing storage allocations. 2039 Like the other operators in \CFA, there is a concise syntax for constructor/destructor function calls:2000 While existing call syntax works for explicit calls to constructors and destructors, \CFA also provides a more concise \newterm{operator syntax} for both: 2040 2001 \begin{cfa} 2041 2002 { 2042 2003 VLA x, y = { 20, 0x01 }, z = y; $\C{// z points to y}$ 2043 // x{}; y{ 20, 0x01 }; z{ z, y };2004 // ?{}( x ); ?{}( y, 20, 0x01 ); ?{}( z, y ); 2044 2005 ^x{}; $\C{// deallocate x}$ 2045 2006 x{}; $\C{// reallocate x}$ … … 2048 2009 y{ x }; $\C{// reallocate y, points to x}$ 2049 2010 x{}; $\C{// reallocate x, not pointing to y}$ 2050 // ^z{}; ^y{}; ^x{};2011 // ^?{}(z); ^?{}(y); ^?{}(x); 2051 2012 } 2052 2013 \end{cfa} … … 2069 2030 In these cases, \CFA provides the initialization syntax \lstinline|S x `@=` {}|, and the object becomes unmanaged, so implicit constructor and destructor calls are not generated. 2070 2031 Any C initializer can be the right-hand side of an \lstinline|@=| initializer, \eg \lstinline|VLA a @= { 0, 0x0 }|, with the usual C initialization semantics. 2071 The same syntax can be used in a compound literal, \eg \lstinline|a = (VLA)`@`{ 0, 0x0 }|, to create a C-style literal.2032 The same syntax can be used in a compound literal, \eg \lstinline|a = VLA`@`{ 0, 0x0 }|, to create a C-style literal. 2072 2033 The point of \lstinline|@=| is to provide a migration path from legacy C code to \CFA, by providing a mechanism to incrementally convert to implicit initialization. 2073 2034 … … 2085 2046 2086 2047 2087 \begin{comment}2088 2048 \subsection{Integral Suffixes} 2089 2049 … … 2119 2079 \lstMakeShortInline@% 2120 2080 \end{cquote} 2121 \end{comment}2122 2081 2123 2082 … … 2125 2084 2126 2085 In C, @0@ has the special property that it is the only ``false'' value; 2127 bythe standard, any value that compares equal to @0@ is false, while any value that compares unequal to @0@ is true.2086 from the standard, any value that compares equal to @0@ is false, while any value that compares unequal to @0@ is true. 2128 2087 As such, an expression @x@ in any boolean context (such as the condition of an @if@ or @while@ statement, or the arguments to @&&@, @||@, or @?:@\,) can be rewritten as @x != 0@ without changing its semantics. 2129 2088 Operator overloading in \CFA provides a natural means to implement this truth-value comparison for arbitrary types, but the C type system is not precise enough to distinguish an equality comparison with @0@ from an equality comparison with an arbitrary integer or pointer. … … 2160 2119 \lstDeleteShortInline@% 2161 2120 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{}} 2162 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{postfix function}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{constant}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{variable/expression}} & \multicolumn{1}{c@{}}{\textbf{postfix pointer}} \\2121 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{postfix function}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{constant}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{variable/expression}} & \multicolumn{1}{c}{\textbf{postfix pointer}} \\ 2163 2122 \begin{cfa} 2164 2123 int |?`h|( int s ); … … 2205 2164 \lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}} 2206 2165 \lstDeleteShortInline@% 2207 \begin{tabular}{@{}l@{\hspace{ 1.25\parindentlnth}}l@{}}2208 \multicolumn{1}{ @{}c@{\hspace{1.25\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{\CC}} \\2166 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2167 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{\CC}} \\ 2209 2168 \begin{cfa} 2210 2169 struct W { … … 2250 2209 W w, heavy = { 20 }; 2251 2210 w = 155|_lb|; 2252 //binary unsupported2211 w = 0b1111|_lb|; // error, binary unsupported 2253 2212 w = 0${\color{red}\LstBasicStyle{'}}$233|_lb|; // quote separator 2254 2213 w = 0x9b|_kg|; … … 2280 2239 \lstDeleteShortInline@% 2281 2240 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2282 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c@{}}{\textbf{Usage}} \\2241 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c}{\textbf{Usage}} \\ 2283 2242 \begin{cfa} 2284 2243 const short int `MIN` = -32768; … … 2298 2257 \begin{cquote} 2299 2258 \lstDeleteShortInline@% 2300 \begin{tabular}{@{}l@{\hspace{ \parindentlnth}}l@{}}2301 \multicolumn{1}{ @{}c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\2259 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2260 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 2302 2261 \begin{cfa} 2303 2262 MIN … … 2308 2267 & 2309 2268 \begin{cfa} 2310 CHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN, FLT_MIN, DBL_MIN, LDBL_MIN2311 UCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX, FLT_MAX, DBL_MAX, LDBL_MAX2269 SCHAR_MIN, CHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN, FLT_MIN, DBL_MIN, LDBL_MIN 2270 SCHAR_MAX, UCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX, FLT_MAX, DBL_MAX, LDBL_MAX 2312 2271 M_PI, M_PIl 2313 2272 M_E, M_El … … 2325 2284 \lstDeleteShortInline@% 2326 2285 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2327 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c@{}}{\textbf{Usage}} \\2286 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c}{\textbf{Usage}} \\ 2328 2287 \begin{cfa} 2329 2288 float `log`( float x ); … … 2344 2303 \lstDeleteShortInline@% 2345 2304 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2346 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\2305 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 2347 2306 \begin{cfa} 2348 2307 log … … 2372 2331 \lstDeleteShortInline@% 2373 2332 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2374 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c@{}}{\textbf{Usage}} \\2333 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c}{\textbf{Usage}} \\ 2375 2334 \begin{cfa} 2376 2335 unsigned int `abs`( int ); … … 2391 2350 \lstDeleteShortInline@% 2392 2351 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2393 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\2352 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 2394 2353 \begin{cfa} 2395 2354 abs … … 2414 2373 an allocation with a specified character. 2415 2374 \item[resize] 2416 an existing allocation to decrease or increaseits size.2375 an existing allocation to decreased or increased its size. 2417 2376 In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied. 2418 2377 For an increase in storage size, new storage after the copied data may be filled. … … 2428 2387 2429 2388 \begin{table} 2430 \caption{Storage-Management Operations}2431 \label{t:StorageManagementOperations}2432 2389 \centering 2433 2390 \lstDeleteShortInline@% … … 2449 2406 \lstDeleteShortInline~% 2450 2407 \lstMakeShortInline@% 2408 \caption{Storage-Management Operations} 2409 \label{t:StorageManagementOperations} 2451 2410 \end{table} 2452 2411 2453 2412 \begin{figure} 2454 2413 \centering 2455 \begin{cfa}[aboveskip=0pt,xleftmargin=0pt] 2414 \begin{cquote} 2415 \begin{cfa}[aboveskip=0pt] 2456 2416 size_t dim = 10; $\C{// array dimension}$ 2457 2417 char fill = '\xff'; $\C{// initialization fill value}$ … … 2459 2419 \end{cfa} 2460 2420 \lstDeleteShortInline@% 2461 \begin{tabular}{@{}l@{\hspace{ \parindentlnth}}l@{}}2462 \multicolumn{1}{ @{}c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\2463 \begin{cfa} [xleftmargin=-10pt]2421 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2422 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 2423 \begin{cfa} 2464 2424 ip = alloc(); 2465 2425 ip = alloc( fill ); … … 2476 2436 & 2477 2437 \begin{cfa} 2478 ip = (int *)malloc( sizeof( int) );2479 ip = (int *)malloc( sizeof( int) ); memset( ip, fill, sizeof(int) );2480 ip = (int *)malloc( dim * sizeof( int) );2481 ip = (int *)malloc( sizeof( int) ); memset( ip, fill, dim * sizeof(int) );2482 ip = (int *)realloc( ip, 2 * dim * sizeof( int) );2483 ip = (int *)realloc( ip, 4 * dim * sizeof( int) ); memset( ip, fill, 4 * dim * sizeof(int));2484 2485 ip = memalign( 16, sizeof( int) );2486 ip = memalign( 16, sizeof( int) ); memset( ip, fill, sizeof(int) );2487 ip = memalign( 16, dim * sizeof( int) );2488 ip = memalign( 16, dim * sizeof( int) ); memset( ip, fill, dim * sizeof(int) );2438 ip = (int *)malloc( sizeof( int ) ); 2439 ip = (int *)malloc( sizeof( int ) ); memset( ip, fill, sizeof( int ) ); 2440 ip = (int *)malloc( dim * sizeof( int ) ); 2441 ip = (int *)malloc( sizeof( int ) ); memset( ip, fill, dim * sizeof( int ) ); 2442 ip = (int *)realloc( ip, 2 * dim * sizeof( int ) ); 2443 ip = (int *)realloc( ip, 4 * dim * sizeof( int ) ); memset( ip, fill, 4 * dim * sizeof( int ) ); 2444 2445 ip = memalign( 16, sizeof( int ) ); 2446 ip = memalign( 16, sizeof( int ) ); memset( ip, fill, sizeof( int ) ); 2447 ip = memalign( 16, dim * sizeof( int ) ); 2448 ip = memalign( 16, dim * sizeof( int ) ); memset( ip, fill, dim * sizeof( int ) ); 2489 2449 \end{cfa} 2490 2450 \end{tabular} 2491 2451 \lstMakeShortInline@% 2452 \end{cquote} 2492 2453 \caption{\CFA versus C Storage-Allocation} 2493 2454 \label{f:StorageAllocation} … … 2502 2463 S * as = anew( dim, 2, 3 ); $\C{// each array element initialized to 2, 3}$ 2503 2464 \end{cfa} 2504 Note, \CC can only initializ earray elements via the default constructor.2465 Note, \CC can only initialization array elements via the default constructor. 2505 2466 2506 2467 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. … … 2519 2480 \lstDeleteShortInline@% 2520 2481 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2521 \multicolumn{1}{ @{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{\CC}} \\2482 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{\CC}} \\ 2522 2483 \begin{cfa} 2523 2484 int x = 1, y = 2, z = 3; … … 2574 2535 \end{cquote} 2575 2536 There is a weak similarity between the \CFA logical-or operator and the Shell pipe-operator for moving data, where data flows in the correct direction for input but the opposite direction for output. 2576 \begin{comment} 2537 2577 2538 The implicit separator character (space/blank) is a separator not a terminator. 2578 2539 The rules for implicitly adding the separator are: … … 2593 2554 }% 2594 2555 \end{itemize} 2595 \end{comment}2596 2556 There are functions to set and get the separator string, and manipulators to toggle separation on and off in the middle of output. 2597 2557 … … 2608 2568 \centering 2609 2569 \lstDeleteShortInline@% 2610 \begin{tabular}{@{}l@{\hspace{ 3\parindentlnth}}l@{}}2611 \multicolumn{1}{ @{}c@{\hspace{3\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\2570 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}@{\hspace{2\parindentlnth}}l@{}} 2571 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{2\parindentlnth}}c}{\textbf{C}} \\ 2612 2572 \begin{cfa} 2613 2573 #include <gmp> … … 2642 2602 2643 2603 2644 \section{ PolymorphismEvaluation}2604 \section{Evaluation} 2645 2605 \label{sec:eval} 2646 2606 2647 \CFA adds parametric polymorphism to C. 2648 A runtime evaluation is performed to compare the cost of alternative styles of polymorphism. 2649 The goal is to compare just the underlying mechanism for implementing different kinds of polymorphism. 2650 % Though \CFA provides significant added functionality over C, these features have a low runtime penalty. 2651 % In fact, it is shown that \CFA's generic programming can enable faster runtime execution than idiomatic @void *@-based C code. 2652 The experiment is a set of generic-stack micro-benchmarks~\cite{CFAStackEvaluation} in C, \CFA, and \CC (see implementations in Appendix~\ref{sec:BenchmarkStackImplementations}). 2607 Though \CFA provides significant added functionality over C, these features have a low runtime penalty. 2608 In fact, \CFA's features for generic programming can enable faster runtime execution than idiomatic @void *@-based C code. 2609 This claim is demonstrated through a set of generic-code-based micro-benchmarks in C, \CFA, and \CC (see stack implementations in Appendix~\ref{sec:BenchmarkStackImplementation}). 2653 2610 Since all these languages share a subset essentially comprising standard C, maximal-performance benchmarks should show little runtime variance, differing only in length and clarity of source code. 2654 2611 A more illustrative comparison measures the costs of idiomatic usage of each language's features. … … 2681 2638 \end{figure} 2682 2639 2683 The structure of each benchmark implemented is: C with @void *@-based polymorphism, \CFA with parametric polymorphism, \CC with templates, and \CC using only class inheritance for polymorphism, called \CCV.2640 The structure of each benchmark implemented is: C with @void *@-based polymorphism, \CFA with the presented features, \CC with templates, and \CC using only class inheritance for polymorphism, called \CCV. 2684 2641 The \CCV variant illustrates an alternative object-oriented idiom where all objects inherit from a base @object@ class, mimicking a Java-like interface; 2685 2642 hence runtime checks are necessary to safely down-cast objects. 2686 2643 The most notable difference among the implementations is in memory layout of generic types: \CFA and \CC inline the stack and pair elements into corresponding list and pair nodes, while C and \CCV lack such a capability and instead must store generic objects via pointers to separately-allocated objects. 2687 Note , the C benchmark uses unchecked casts as C has no runtime mechanism to perform such checks, while \CFA and \CC provide type-safety statically.2644 Note that the C benchmark uses unchecked casts as there is no runtime mechanism to perform such checks, while \CFA and \CC provide type-safety statically. 2688 2645 2689 2646 Figure~\ref{fig:eval} and Table~\ref{tab:eval} show the results of running the benchmark in Figure~\ref{fig:BenchmarkTest} and its C, \CC, and \CCV equivalents. 2690 2647 The graph plots the median of 5 consecutive runs of each program, with an initial warm-up run omitted. 2691 All code is compiled at \texttt{-O2} by gcc or g++ 6. 4.0, with all \CC code compiled as \CCfourteen.2648 All code is compiled at \texttt{-O2} by gcc or g++ 6.3.0, with all \CC code compiled as \CCfourteen. 2692 2649 The benchmarks are run on an Ubuntu 16.04 workstation with 16 GB of RAM and a 6-core AMD FX-6300 CPU with 3.5 GHz maximum clock frequency. 2693 2650 … … 2700 2657 2701 2658 \begin{table} 2659 \centering 2702 2660 \caption{Properties of benchmark code} 2703 2661 \label{tab:eval} 2704 \centering2705 2662 \newcommand{\CT}[1]{\multicolumn{1}{c}{#1}} 2706 2663 \begin{tabular}{rrrrr} 2707 2664 & \CT{C} & \CT{\CFA} & \CT{\CC} & \CT{\CCV} \\ \hline 2708 2665 maximum memory usage (MB) & 10,001 & 2,502 & 2,503 & 11,253 \\ 2709 source code size (lines) & 201 & 191 & 125 & 294\\2666 source code size (lines) & 196 & 186 & 125 & 290 \\ 2710 2667 redundant type annotations (lines) & 27 & 0 & 2 & 16 \\ 2711 2668 binary size (KB) & 14 & 257 & 14 & 37 \\ … … 2715 2672 The C and \CCV variants are generally the slowest with the largest memory footprint, because of their less-efficient memory layout and the pointer-indirection necessary to implement generic types; 2716 2673 this inefficiency is exacerbated by the second level of generic types in the pair benchmarks. 2717 By contrast, the \CFA and \CC variants run in roughly equivalent time for both the integer and pair because of equivalent storage layout, with the inlined libraries (\ie no separate compilation) and greater maturity of the \CC compiler contributing to its lead.2674 By contrast, the \CFA and \CC variants run in roughly equivalent time for both the integer and pair of @short@ and @char@ because the storage layout is equivalent, with the inlined libraries (\ie no separate compilation) and greater maturity of the \CC compiler contributing to its lead. 2718 2675 \CCV is slower than C largely due to the cost of runtime type-checking of down-casts (implemented with @dynamic_cast@); 2719 The outlier for \CFA, pop @pair@, results from the complexity of the generated-C polymorphic code. 2720 The gcc compiler is unable to optimize some dead code and condense nested calls; 2721 a compiler designed for \CFA could easily perform these optimizations. 2676 The outlier in the graph for \CFA, pop @pair@, results from the complexity of the generated-C polymorphic code. 2677 The gcc compiler is unable to optimize some dead code and condense nested calls; a compiler designed for \CFA could easily perform these optimizations. 2722 2678 Finally, the binary size for \CFA is larger because of static linking with the \CFA libraries. 2723 2679 … … 2731 2687 Line-count is a fairly rough measure of code complexity; 2732 2688 another important factor is how much type information the programmer must specify manually, especially where that information is not compiler-checked. 2733 Such unchecked type information produces a heavier documentation burden and increased potential for runtime bugs, and is much less common in \CFA than C, with its manually specified function pointer arguments and format codes, or \CCV, with its extensive use of un -type-checked downcasts, \eg @object@ to @integer@ when popping a stack.2689 Such unchecked type information produces a heavier documentation burden and increased potential for runtime bugs, and is much less common in \CFA than C, with its manually specified function pointer arguments and format codes, or \CCV, with its extensive use of untype-checked downcasts, \eg @object@ to @integer@ when popping a stack. 2734 2690 To quantify this manual typing, the ``redundant type annotations'' line in Table~\ref{tab:eval} counts the number of lines on which the type of a known variable is respecified, either as a format specifier, explicit downcast, type-specific function, or by name in a @sizeof@, struct literal, or @new@ expression. 2735 2691 The \CC benchmark uses two redundant type annotations to create a new stack nodes, while the C and \CCV benchmarks have several such annotations spread throughout their code. 2736 2692 The \CFA benchmark is able to eliminate all redundant type annotations through use of the polymorphic @alloc@ function discussed in Section~\ref{sec:libraries}. 2737 2693 2738 We conjecture these results scale across most generic data-types as the underlying polymorphism implement is constant.2739 2740 2694 2741 2695 \section{Related Work} … … 2743 2697 2744 2698 \subsection{Polymorphism} 2745 2746 ML~\cite{ML} was the first language to support parametric polymorphism.2747 Like \CFA, it supports universal type parameters, but not the use of assertions and traits to constrain type arguments.2748 Haskell~\cite{Haskell10} combines ML-style polymorphism, polymorphic data types, and type inference with the notion of type classes, collections of overloadable methods that correspond in intent to traits in \CFA.2749 Unlike \CFA, Haskell requires an explicit association between types and their classes that specifies the implementation of operations.2750 These associations determine the functions that are assertion arguments for particular combinations of class and type, in contrast to \CFA where the assertion arguments are selected at function call sites based upon the set of operations in scope at that point.2751 Haskell also severely restricts the use of overloading: an overloaded name can only be associated with a single class, and methods with overloaded names can only be defined as part of instance declarations.2752 2699 2753 2700 \CC provides three disjoint polymorphic extensions to C: overloading, inheritance, and templates. … … 2803 2750 Go does not have tuples but supports MRVF. 2804 2751 Java's variadic functions appear similar to C's but are type-safe using homogeneous arrays, which are less useful than \CFA's heterogeneously-typed variadic functions. 2805 Tuples are a fundamental abstraction in most functional programming languages, such as Standard ML~\cite{sml} , Haskell, and Scala~\cite{Scala}, which decompose tuples using pattern matching.2752 Tuples are a fundamental abstraction in most functional programming languages, such as Standard ML~\cite{sml} and~\cite{Scala}, which decompose tuples using pattern matching. 2806 2753 2807 2754 … … 2820 2767 data-parallel features have not yet been added to \CFA, but are easily incorporated within its design, while concurrency primitives similar to those in $\mu$\CC have already been added~\cite{Delisle18}. 2821 2768 Finally, CCured~\cite{Necula02} and Ironclad \CC~\cite{DeLozier13} attempt to provide a more memory-safe C by annotating pointer types with garbage collection information; type-checked polymorphism in \CFA covers several of C's memory-safety issues, but more aggressive approaches such as annotating all pointer types with their nullability or requiring runtime garbage collection are contradictory to \CFA's backwards compatibility goals. 2769 2770 2771 \begin{comment} 2772 \subsection{Control Structures / Declarations / Literals} 2773 2774 Java has default fall through like C/\CC. 2775 Pascal/Ada/Go/Rust do not have default fall through. 2776 \Csharp does not have fall through but still requires a break. 2777 Python uses dictionary mapping. \\ 2778 \CFA choose is like Rust match. 2779 2780 Java has labelled break/continue. \\ 2781 Languages with and without exception handling. 2782 2783 Alternative C declarations. \\ 2784 Different references \\ 2785 Constructors/destructors 2786 2787 0/1 Literals \\ 2788 user defined: D, Objective-C 2789 \end{comment} 2822 2790 2823 2791 … … 2834 2802 Finally, we demonstrate that \CFA performance for some idiomatic cases is better than C and close to \CC, showing the design is practically applicable. 2835 2803 2836 While all examples in the paper compile and run, a public beta-release of \CFA will take 6--8 months to reduce compilation time, provide better debugging, and add a few more libraries. 2837 There is also new work on a number of \CFA features, including arrays with size, runtime type-information, virtual functions, user-defined conversions, and modules. 2838 While \CFA polymorphic functions use dynamic virtual-dispatch with low runtime overhead (see Section~\ref{sec:eval}), it is not as low as \CC template-inlining. 2839 Hence it may be beneficial to provide a mechanism for performance-sensitive code. 2804 There is ongoing work on a wide range of \CFA features, including arrays with size, runtime type-information, virtual functions, user-defined conversions, concurrent primitives, and modules. 2805 While all examples in the paper compile and run, a public beta-release of \CFA will take another 8--12 months to finalize these extensions. 2806 There are also interesting future directions for the polymorphism design. 2807 Notably, \CC template functions trade compile time and code bloat for optimal runtime of individual instantiations of polymorphic functions. 2808 \CFA polymorphic functions use dynamic virtual-dispatch; 2809 the runtime overhead of this approach is low, but not as low as inlining, and it may be beneficial to provide a mechanism for performance-sensitive code. 2840 2810 Two promising approaches are an @inline@ annotation at polymorphic function call sites to create a template-specialization of the function (provided the code is visible) or placing an @inline@ annotation on polymorphic function-definitions to instantiate a specialized version for some set of types (\CC template specialization). 2841 2811 These approaches are not mutually exclusive and allow performance optimizations to be applied only when necessary, without suffering global code-bloat. … … 2846 2816 2847 2817 The authors would like to recognize the design assistance of Glen Ditchfield, Richard Bilson, Thierry Delisle, Andrew Beach and Brice Dobry on the features described in this paper, and thank Magnus Madsen for feedback on the writing. 2848 Funding for this project has been provided by Huawei Ltd.\ (\url{http://www.huawei.com}), and Aaron Moss and Peter Buhr are partially funded by the Natural Sciences and Engineering Research Council of Canada. 2849 2850 {% 2851 \fontsize{9bp}{12bp}\selectfont% 2818 This work is supported by a corporate partnership with Huawei Ltd.\ (\url{http://www.huawei.com}), and Aaron Moss and Peter Buhr are partially funded by the Natural Sciences and Engineering Research Council of Canada. 2819 2820 2852 2821 \bibliography{pl} 2853 }% 2822 2854 2823 2855 2824 \appendix 2856 2825 2857 \section{Benchmark Stack Implementations} 2858 \label{sec:BenchmarkStackImplementations} 2859 2860 Throughout, @/***/@ designates a counted redundant type annotation; code reformatted slightly for brevity. 2861 2862 2863 \subsection{C} 2864 2865 \begin{flushleft} 2866 \lstDeleteShortInline@% 2867 \begin{tabular}{@{}l@{\hspace{1.8\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}} 2868 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 2869 typedef struct node { 2826 \section{Benchmark Stack Implementation} 2827 \label{sec:BenchmarkStackImplementation} 2828 2829 Throughout, @/***/@ designates a counted redundant type annotation; code reformatted for brevity. 2830 2831 \smallskip\noindent 2832 C 2833 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 2834 struct stack_node { 2870 2835 void * value; 2871 struct node * next; 2872 } node; 2873 typedef struct stack { 2874 struct node * head; 2875 } stack; 2876 void copy_stack( stack * s, const stack * t, 2877 void * (*copy)( const void * ) ) { 2878 node ** cr = &s->head; 2879 for (node * nx = t->head; nx; nx = nx->next) { 2880 *cr = malloc( sizeof(node) ); /***/ 2881 (*cr)->value = copy( nx->value ); 2882 cr = &(*cr)->next; 2883 } 2884 *cr = NULL; 2885 } 2886 void clear_stack( stack * s, void (* free_el)( void * ) ) { 2887 for ( node * nx = s->head; nx; ) { 2888 node * cr = nx; 2889 nx = cr->next; 2890 free_el( cr->value ); 2891 free( cr ); 2836 struct stack_node * next; 2837 }; 2838 struct stack { struct stack_node* head; }; 2839 void clear_stack( struct stack * s, void (*free_el)( void * ) ) { 2840 for ( struct stack_node * next = s->head; next; ) { 2841 struct stack_node * crnt = next; 2842 next = crnt->next; 2843 free_el( crnt->value ); 2844 free( crnt ); 2892 2845 } 2893 2846 s->head = NULL; 2894 2847 } 2895 \end{cfa} 2896 & 2897 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 2898 stack new_stack() { 2899 return (stack){ NULL }; /***/ 2900 } 2901 stack * assign_stack( stack * s, const stack * t, 2902 void * (*copy_el)( const void * ), 2903 void (*free_el)( void * ) ) { 2848 struct stack new_stack() { return (struct stack){ NULL }; /***/ } 2849 void copy_stack( struct stack * s, const struct stack * t, void * (*copy)( const void * ) ) { 2850 struct stack_node ** crnt = &s->head; 2851 for ( struct stack_node * next = t->head; next; next = next->next ) { 2852 *crnt = malloc( sizeof(struct stack_node) ); /***/ 2853 (*crnt)->value = copy( next->value ); 2854 crnt = &(*crnt)->next; 2855 } 2856 *crnt = NULL; 2857 } 2858 struct stack * assign_stack( struct stack * s, const struct stack * t, 2859 void * (*copy_el)( const void * ), void (*free_el)( void * ) ) { 2904 2860 if ( s->head == t->head ) return s; 2905 2861 clear_stack( s, free_el ); /***/ … … 2907 2863 return s; 2908 2864 } 2909 _Bool stack_empty( const stack * s ) { 2910 return s->head == NULL; 2911 } 2912 void push_stack( stack * s, void * v ) { 2913 node * n = malloc( sizeof(node) ); /***/ 2914 *n = (node){ v, s->head }; /***/ 2865 _Bool stack_empty( const struct stack * s ) { return s->head == NULL; } 2866 void push_stack( struct stack * s, void * v ) { 2867 struct stack_node * n = malloc( sizeof(struct stack_node) ); /***/ 2868 *n = (struct stack_node){ v, s->head }; /***/ 2915 2869 s->head = n; 2916 2870 } 2917 void * pop_stack( st ack * s ) {2918 node * n = s->head;2871 void * pop_stack( struct stack * s ) { 2872 struct stack_node * n = s->head; 2919 2873 s->head = n->next; 2920 2874 void * v = n->value; … … 2923 2877 } 2924 2878 \end{cfa} 2925 \end{tabular} 2926 \lstMakeShortInline@% 2927 \end{flushleft} 2928 2929 2930 \subsection{\CFA} 2931 \label{s:CforallStack} 2932 2933 \begin{flushleft} 2934 \lstDeleteShortInline@% 2935 \begin{tabular}{@{}l|@{\hspace{\parindentlnth}}l@{}} 2936 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 2879 2880 \medskip\noindent 2881 \CFA 2882 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 2883 forall( otype T ) struct stack_node { 2884 T value; 2885 stack_node(T) * next; 2886 }; 2887 forall( otype T ) struct stack { stack_node(T) * head; }; 2888 forall( otype T ) void clear( stack(T) & s ) with( s ) { 2889 for ( stack_node(T) * next = head; next; ) { 2890 stack_node(T) * crnt = next; 2891 next = crnt->next; 2892 ^(*crnt){}; 2893 free(crnt); 2894 } 2895 head = 0; 2896 } 2897 forall( otype T ) void ?{}( stack(T) & s ) { (s.head){ 0 }; } 2898 forall( otype T ) void ?{}( stack(T) & s, stack(T) t ) { 2899 stack_node(T) ** crnt = &s.head; 2900 for ( stack_node(T) * next = t.head; next; next = next->next ) { 2901 *crnt = alloc(); 2902 ((*crnt)->value){ next->value }; 2903 crnt = &(*crnt)->next; 2904 } 2905 *crnt = 0; 2906 } 2907 forall( otype T ) stack(T) ?=?( stack(T) & s, stack(T) t ) { 2908 if ( s.head == t.head ) return s; 2909 clear( s ); 2910 s{ t }; 2911 return s; 2912 } 2913 forall( otype T ) void ^?{}( stack(T) & s) { clear( s ); } 2914 forall( otype T ) _Bool empty( const stack(T) & s ) { return s.head == 0; } 2915 forall( otype T ) void push( stack(T) & s, T value ) with( s ) { 2916 stack_node(T) * n = alloc(); 2917 (*n){ value, head }; 2918 head = n; 2919 } 2920 forall( otype T ) T pop( stack(T) & s ) with( s ) { 2921 stack_node(T) * n = head; 2922 head = n->next; 2923 T v = n->value; 2924 ^(*n){}; 2925 free( n ); 2926 return v; 2927 } 2928 \end{cfa} 2929 2930 \begin{comment} 2937 2931 forall( otype T ) { 2938 struct node {2932 struct stack_node { 2939 2933 T value; 2940 node(T) * next;2934 stack_node(T) * next; 2941 2935 }; 2942 struct stack { node(T) * head; }; 2943 void ?{}( stack(T) & s, stack(T) t ) { // copy 2944 node(T) ** cr = &s.head; 2945 for ( node(T) * nx = t.head; nx; nx = nx->next ) { 2946 *cr = alloc(); 2947 ((*cr)->value){ nx->value }; 2948 cr = &(*cr)->next; 2949 } 2950 *cr = 0; 2951 } 2936 struct stack { stack_node(T) * head; }; 2952 2937 void clear( stack(T) & s ) with( s ) { 2953 for ( node(T) * nx = head; nx; ) {2954 node(T) * cr = nx;2955 n x = cr->next;2956 ^(*cr ){};2957 free( cr);2938 for ( stack_node(T) * next = head; next; ) { 2939 stack_node(T) * crnt = next; 2940 next = crnt->next; 2941 ^(*crnt){}; 2942 free(crnt); 2958 2943 } 2959 2944 head = 0; 2960 2945 } 2961 2962 \end{cfa}2963 &2964 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt]2965 2946 void ?{}( stack(T) & s ) { (s.head){ 0 }; } 2966 void ^?{}( stack(T) & s) { clear( s ); } 2947 void ?{}( stack(T) & s, stack(T) t ) { 2948 stack_node(T) ** crnt = &s.head; 2949 for ( stack_node(T) * next = t.head; next; next = next->next ) { 2950 *crnt = alloc(); 2951 ((*crnt)->value){ next->value }; 2952 crnt = &(*crnt)->next; 2953 } 2954 *crnt = 0; 2955 } 2967 2956 stack(T) ?=?( stack(T) & s, stack(T) t ) { 2968 2957 if ( s.head == t.head ) return s; … … 2971 2960 return s; 2972 2961 } 2973 _Bool empty( const stack(T) & s ) { 2974 return s.head == 0; 2975 } 2962 void ^?{}( stack(T) & s) { clear( s ); } 2963 _Bool empty( const stack(T) & s ) { return s.head == 0; } 2976 2964 void push( stack(T) & s, T value ) with( s ) { 2977 node(T) * n = alloc();2965 stack_node(T) * n = alloc(); 2978 2966 (*n){ value, head }; 2979 2967 head = n; 2980 2968 } 2981 2969 T pop( stack(T) & s ) with( s ) { 2982 node(T) * n = head;2970 stack_node(T) * n = head; 2983 2971 head = n->next; 2984 2972 T v = n->value; … … 2988 2976 } 2989 2977 } 2990 \end{cfa} 2991 \end{tabular} 2992 \lstMakeShortInline@% 2993 \end{flushleft} 2994 2995 2996 \subsection{\CC} 2997 2998 \begin{flushleft} 2999 \lstDeleteShortInline@% 3000 \begin{tabular}{@{}l|@{\hspace{\parindentlnth}}l@{}} 3001 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 2978 \end{comment} 2979 2980 \medskip\noindent 2981 \CC 2982 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 3002 2983 template<typename T> struct stack { 3003 2984 struct node { 3004 2985 T value; 3005 2986 node * next; 3006 node( const T & v, node * n = nullptr ) : 3007 value( v ), next( n ) {} 2987 node( const T & v, node * n = nullptr ) : value( v ), next( n ) {} 3008 2988 }; 3009 2989 node * head; 3010 void copy( const stack<T> & o ) { 3011 node ** cr = &head; 3012 for ( node * nx = o.head; nx; nx = nx->next ) { 3013 *cr = new node{ nx->value }; /***/ 3014 cr = &(*cr)->next; 3015 } 3016 *cr = nullptr; 3017 } 2990 stack() : head( nullptr ) {} 2991 stack( const stack<T> & o ) { copy( o ); } 3018 2992 void clear() { 3019 for ( node * n x = head; nx; ) {3020 node * cr = nx;3021 n x = cr->next;3022 delete cr ;2993 for ( node * next = head; next; ) { 2994 node * crnt = next; 2995 next = crnt->next; 2996 delete crnt; 3023 2997 } 3024 2998 head = nullptr; 3025 2999 } 3026 \end{cfa} 3027 & 3028 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 3029 stack() : head( nullptr ) {} 3030 stack( const stack<T> & o ) { copy( o ); } 3000 void copy( const stack<T> & o ) { 3001 node ** crnt = &head; 3002 for ( node * next = o.head; next; next = next->next ) { 3003 *crnt = new node{ next->value }; /***/ 3004 crnt = &(*crnt)->next; 3005 } 3006 *crnt = nullptr; 3007 } 3031 3008 ~stack() { clear(); } 3032 stack & operator= ( const stack<T> & o ) {3009 stack & operator= ( const stack<T> & o ) { 3033 3010 if ( this == &o ) return *this; 3034 3011 clear(); … … 3036 3013 return *this; 3037 3014 } 3038 bool empty() const { 3039 return head == nullptr; 3040 } 3041 void push( const T & value ) { 3042 head = new node{ value, head }; /***/ 3043 } 3015 bool empty() const { return head == nullptr; } 3016 void push( const T & value ) { head = new node{ value, head }; /***/ } 3044 3017 T pop() { 3045 3018 node * n = head; … … 3050 3023 } 3051 3024 }; 3052 3053 \end{cfa} 3054 \end{tabular} 3055 \lstMakeShortInline@% 3056 \end{flushleft} 3057 3058 3059 \subsection{\CCV} 3060 3061 \begin{flushleft} 3062 \lstDeleteShortInline@% 3063 \begin{tabular}{@{}l|@{\hspace{\parindentlnth}}l@{}} 3064 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 3025 \end{cfa} 3026 3027 \medskip\noindent 3028 \CCV 3029 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 3065 3030 struct stack { 3066 3031 struct node { 3067 3032 ptr<object> value; 3068 3033 node * next; 3069 node( const object & v, node * n = nullptr ) : 3070 value( v.new_copy() ), next( n ) {} 3034 node( const object & v, node * n = nullptr ) : value( v.new_copy() ), next( n ) {} 3071 3035 }; 3072 3036 node * head; 3073 void copy( const stack & o ) {3074 node ** cr = &head;3075 for ( node * nx = o.head; nx; nx = nx->next ) {3076 *cr = new node{ *nx->value }; /***/3077 cr = &(*cr)->next;3078 }3079 *cr = nullptr;3080 }3081 3037 void clear() { 3082 for ( node * n x = head; nx; ) {3083 node * cr = nx;3084 n x = cr->next;3085 delete cr ;3038 for ( node * next = head; next; ) { 3039 node * crnt = next; 3040 next = crnt->next; 3041 delete crnt; 3086 3042 } 3087 3043 head = nullptr; 3088 3044 } 3089 \end{cfa} 3090 & 3091 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 3045 void copy( const stack & o ) { 3046 node ** crnt = &head; 3047 for ( node * next = o.head; next; next = next->next ) { 3048 *crnt = new node{ *next->value }; /***/ 3049 crnt = &(*crnt)->next; 3050 } 3051 *crnt = nullptr; 3052 } 3092 3053 stack() : head( nullptr ) {} 3093 3054 stack( const stack & o ) { copy( o ); } 3094 3055 ~stack() { clear(); } 3095 stack & operator= ( const stack & o ) {3056 stack & operator= ( const stack & o ) { 3096 3057 if ( this == &o ) return *this; 3097 3058 clear(); … … 3099 3060 return *this; 3100 3061 } 3101 bool empty() const { 3102 return head == nullptr; 3103 } 3104 void push( const object & value ) { 3105 head = new node{ value, head }; /***/ 3106 } 3062 bool empty() const { return head == nullptr; } 3063 void push( const object & value ) { head = new node{ value, head }; /***/ } 3107 3064 ptr<object> pop() { 3108 3065 node * n = head; … … 3113 3070 } 3114 3071 }; 3115 3116 \end{cfa} 3117 \end{tabular} 3118 \lstMakeShortInline@% 3119 \end{flushleft} 3072 \end{cfa} 3120 3073 3121 3074
Note:
See TracChangeset
for help on using the changeset viewer.