Changeset ff29f08 for doc/papers/general
- Timestamp:
- May 18, 2018, 2:09:21 PM (7 years ago)
- Branches:
- new-env, with_gc
- Children:
- 2472a19
- Parents:
- f6f0cca3 (diff), c7d8100c (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:
-
- 1 added
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/papers/general/.gitignore
rf6f0cca3 rff29f08 8 8 Paper.out.ps 9 9 WileyNJD-AMA.bst 10 evaluation.zip -
doc/papers/general/Makefile
rf6f0cca3 rff29f08 45 45 @rm -frv ${DOCUMENT} ${BASE}.ps WileyNJD-AMA.bst ${BASE}.out.ps ${Build} 46 46 47 Paper.zip : 48 zip -x general/.gitignore -x general/"*AMA*" -x general/Paper.out.ps -x general/Paper.tex.plain -x general/evaluation.zip -x general/mail -x general/response -x general/test.c -x general/evaluation.zip -x general/Paper.tex.plain -x general/Paper.ps -x general/Paper.pdf -x general/"*build*" -x general/evaluation/.gitignore -x general/evaluation/timing.xlsx -r Paper.zip general 49 50 evaluation.zip : 51 zip -x evaluation/.gitignore -x evaluation/timing.xlsx -x evaluation/timing.dat -r evaluation.zip evaluation 52 47 53 # File Dependencies # 48 54 … … 66 72 ## Define the default recipes. 67 73 68 ${Build} :74 ${Build} : 69 75 mkdir -p ${Build} 70 76 71 ${BASE}.out.ps :72 ln -fs build/Paper.out.ps .77 ${BASE}.out.ps : ${Build} 78 ln -fs ${Build}/Paper.out.ps . 73 79 74 WileyNJD-AMA.bst :80 WileyNJD-AMA.bst : 75 81 ln -fs ../AMA/AMA-stix/ama/WileyNJD-AMA.bst . 76 82 77 ${GRAPHS} : timing.gp timing.dat83 ${GRAPHS} : ${Build} timing.gp timing.dat 78 84 gnuplot -e Build="'${Build}/'" evaluation/timing.gp 79 85 80 %.tex : %.fig 86 %.tex : %.fig ${Build} 81 87 fig2dev -L eepic $< > ${Build}/$@ 82 88 83 %.ps : %.fig 89 %.ps : %.fig ${Build} 84 90 fig2dev -L ps $< > ${Build}/$@ 85 91 86 %.pstex : %.fig 92 %.pstex : %.fig ${Build} 87 93 fig2dev -L pstex $< > ${Build}/$@ 88 94 fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t -
doc/papers/general/Paper.tex
rf6f0cca3 rff29f08 54 54 \newcommand{\TODO}[1]{} % TODO elided 55 55 56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 57 56 58 % Default underscore is too low and wide. Cannot use lstlisting "literate" as replacing underscore 57 59 % removes it as a variable-name character so keywords in variables are highlighted. MUST APPEAR … … 60 62 \renewcommand{\textunderscore}{\leavevmode\makebox[1.2ex][c]{\rule{1ex}{0.075ex}}} 61 63 64 \renewcommand*{\thefootnote}{\Alph{footnote}} % hack because fnsymbol does not work 65 %\renewcommand*{\thefootnote}{\fnsymbol{footnote}} 66 62 67 \makeatletter 63 68 % parindent is relative, i.e., toggled on/off in environments like itemize, so store the value for … … 74 79 \setlength{\gcolumnposn}{3.5in} 75 80 \setlength{\columnposn}{\gcolumnposn} 81 76 82 \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}}}} 77 83 \newcommand{\CRT}{\global\columnposn=\gcolumnposn} … … 159 165 literate={-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.1ex}}}}1 {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1 160 166 {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1 % {`}{\ttfamily\upshape\hspace*{-0.1ex}`}1 161 {<-}{$\leftarrow$}2 {=>}{$\Rightarrow$}2 {->}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.8ex}{0.075ex}}}\kern-0.2ex{\textgreater}}2, 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, 162 169 moredelim=**[is][\color{red}]{`}{`}, 163 170 }% lstset … … 173 180 \lstMakeShortInline@% 174 181 182 \let\OLDthebibliography\thebibliography 183 \renewcommand\thebibliography[1]{ 184 \OLDthebibliography{#1} 185 \setlength{\parskip}{0pt} 186 \setlength{\itemsep}{4pt plus 0.3ex} 187 } 175 188 176 189 \title{\texorpdfstring{\protect\CFA : Adding Modern Programming Language Features to C}{Cforall : Adding Modern Programming Language Features to C}} … … 190 203 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. 191 204 This installation base and the programmers producing it represent a massive software-engineering investment spanning decades and likely to continue for decades more. 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. 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. 196 210 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. 197 211 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. … … 227 241 Love it or hate it, C is extremely popular, highly used, and one of the few systems languages. 228 242 In many cases, \CC is often used solely as a better C. 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 a ims to add modern languagefeatures to C, while maintaining both source and runtime compatibility with C and a familiar programming model for programmers.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 adds modern language-features to C, while maintaining both source and runtime compatibility with C and a familiar programming model for programmers. 232 246 The four key design goals for \CFA~\cite{Bilson03} are: 233 247 (1) The behaviour of standard C code must remain the same when translated by a \CFA compiler as when translated by a C compiler; … … 238 252 \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. 239 253 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). 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). 241 257 Ultimately, a compiler is necessary for advanced features and optimal performance. 242 All features discussed in this paper are working, unless otherwise stated as under construction. 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. 243 310 244 311 Finally, it is impossible to describe a programming language without usages before definitions. … … 261 328 There are only two hard things in Computer Science: cache invalidation and \emph{naming things} -- Phil Karlton 262 329 \end{quote} 330 \vspace{-9pt} 263 331 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. 264 332 \CFA extends the built-in operator overloading by allowing users to define overloads for any function, not just operators, and even any variable; … … 266 334 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. 267 335 As an example: 268 269 \begin{cfa} 270 int max = 2147483647; $\C[4in]{// (1)}$ 271 double max = 1.7976931348623157E+308; $\C{// (2)}$ 336 \begin{cfa} 337 int max = 2147483647; $\C[4in]{// (1)}$ 338 double max = 1.7976931348623157E+308; $\C{// (2)}$ 272 339 int max( int a, int b ) { return a < b ? b : a; } $\C{// (3)}$ 273 340 double max( double a, double b ) { return a < b ? b : a; } $\C{// (4)}\CRT$ 274 max( 7, -max ); $\C [2.75in]{// uses (3) and (1), by matching int from constant 7}$341 max( 7, -max ); $\C{// uses (3) and (1), by matching int from constant 7}$ 275 342 max( max, 3.14 ); $\C{// uses (4) and (2), by matching double from constant 3.14}$ 276 max( max, -max ); $\C{// ERROR :ambiguous}$277 int m = max( max, -max ); $\C{// uses (3) and (1) twice, by matching return type} \CRT$343 max( max, -max ); $\C{// ERROR, ambiguous}$ 344 int m = max( max, -max ); $\C{// uses (3) and (1) twice, by matching return type}$ 278 345 \end{cfa} 279 346 … … 284 351 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. 285 352 286 \Celeven added @_Generic@ expressions , which is used in preprocessor macros to provide a form ofad-hoc polymorphism;353 \Celeven added @_Generic@ expressions~\cite[\S~6.5.1.1]{C11}, which is used with preprocessor macros to provide ad-hoc polymorphism; 287 354 however, this polymorphism is both functionally and ergonomically inferior to \CFA name overloading. 288 355 The macro wrapping the generic expression imposes some limitations; 289 356 \eg, it cannot implement the example above, because the variables @max@ are ambiguous with the functions @max@. 290 357 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. 291 For backwards compatibility, \CFA supports @_Generic@ expressions, but it is an unnecessary mechanism. \TODO{actually implement that}358 \CFA supports @_Generic@ expressions for backwards compatibility, but it is an unnecessary mechanism. \TODO{actually implement that} 292 359 293 360 % http://fanf.livejournal.com/144696.html … … 317 384 \begin{cfa} 318 385 forall( otype T `| { T ?+?(T, T); }` ) T twice( T x ) { return x `+` x; } $\C{// ? denotes operands}$ 319 int val = twice( twice( 3.7 ) ); 386 int val = twice( twice( 3.7 ) ); $\C{// val == 14}$ 320 387 \end{cfa} 321 388 which works for any type @T@ with a matching addition operator. 322 389 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@. 323 390 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. 324 The first approach has a late conversion from @double@ to @int@ on the final assignment, while the second has an ea gerconversion to @int@.391 The first approach has a late conversion from @double@ to @int@ on the final assignment, while the second has an early conversion to @int@. 325 392 \CFA minimizes the number of conversions and their potential to lose information, so it selects the first approach, which corresponds with C-programmer intuition. 326 393 … … 329 396 A simple example is leveraging the existing type-unsafe (@void *@) C @bsearch@ to binary search a sorted float array: 330 397 \begin{cfa} 331 void * bsearch( const void * key, const void * base, size_t nmemb, size_t size, int (* compar)( const void *, const void * )); 398 void * bsearch( const void * key, const void * base, size_t nmemb, size_t size, 399 int (* compar)( const void *, const void * )); 332 400 int comp( const void * t1, const void * t2 ) { 333 401 return *(double *)t1 < *(double *)t2 ? -1 : *(double *)t2 < *(double *)t1 ? 1 : 0; … … 355 423 356 424 \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}). 357 For example, it is possible to write a type-safe \CFA wrapper @malloc@ based on the C @malloc@ :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. 358 426 \begin{cfa} 359 427 forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); } 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. 428 // select type and size from left-hand side 429 int * ip = malloc(); double * dp = malloc(); struct S {...} * sp = malloc(); 430 \end{cfa} 365 431 366 432 Call-site inferencing and nested functions provide a localized form of inheritance. … … 369 435 \begin{cfa} 370 436 forall( otype T | { int ?<?( T, T ); } ) void qsort( const T * arr, size_t size ) { /* use C qsort */ } 371 {437 int main() { 372 438 int ?<?( double x, double y ) { return x `>` y; } $\C{// locally override behaviour}$ 373 qsort( vals, size );$\C{// descending sort}$374 } 375 \end{cfa} 376 Within the block, the nested version of @?<?@ performs @?>?@ and this local version overridesthe built-in @?<?@ so it is passed to @qsort@.439 qsort( vals, 10 ); $\C{// descending sort}$ 440 } 441 \end{cfa} 442 The local version of @?<?@ performs @?>?@ overriding the built-in @?<?@ so it is passed to @qsort@. 377 443 Hence, programmers can easily form local environments, adding and modifying appropriate functions, to maximize reuse of other existing functions and types. 378 444 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}$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}$ 382 448 struct stack { stack_node(`T`) * head; }; $\C{// generic type}$ 383 void push( stack(`T`) & s, `T` value ) ... $\C{// generic operations}$ 384 T pop( stack(`T`) & s ) ... 385 } 386 \end{cfa} 387 388 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} 389 457 \subsection{Traits} 390 458 391 459 \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: 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 * ); 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 & ); 399 471 }; 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 +}$ 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 + 403 480 return total; 404 481 } 405 482 \end{cfa} 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: 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: 408 489 \begin{cfa} 409 490 trait otype( dtype T | sized(T) ) { // sized is a pseudo-trait for types with known size and alignment … … 423 504 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. 424 505 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. 425 (Nominal inheritance can be approximated with traits using marker variables or functions, as is done in Go.)506 % (Nominal inheritance can be approximated with traits using marker variables or functions, as is done in Go.) 426 507 427 508 % Nominal inheritance can be simulated with traits using marker variables or functions: … … 462 543 463 544 \CC, Java, and other languages use \newterm{generic types} to produce type-safe abstract data-types. 464 \CFA also implements generic types thatintegrate efficiently and naturally with the existing polymorphic functions, while retaining backwards compatibility with C and providing separate compilation.545 \CFA generic types integrate efficiently and naturally with the existing polymorphic functions, while retaining backwards compatibility with C and providing separate compilation. 465 546 However, for known concrete parameters, the generic-type definition can be inlined, like \CC templates. 466 547 467 548 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: 468 \begin{cfa} 469 forall( otype R, otype S ) struct pair { 470 R first; 471 S second; 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; 472 555 }; 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}$ 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 477 564 int i = value( p ); 478 pair( void *, int * ) q = { 0, &p.second }; $\C{// concrete}$565 pair(void *, int *) q = { 0, &p.second }; // concrete 479 566 i = value( q ); 480 567 double d = 1.0; 481 pair( double *, double * ) r = { &d, &d }; $\C{// concrete}$568 pair(double *, double *) r = { &d, &d }; // concrete 482 569 d = value( r ); 483 570 \end{cfa} 571 \end{tabular} 572 \lstMakeShortInline@% 573 \end{cquote} 484 574 485 575 \CFA classifies generic types as either \newterm{concrete} or \newterm{dynamic}. 486 576 Concrete types have a fixed memory layout regardless of type parameters, while dynamic types vary in memory layout depending on their type parameters. 487 577 A \newterm{dtype-static} type has polymorphic parameters but is still concrete. 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. 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. 489 580 490 581 \CFA generic types also allow checked argument-constraints. … … 503 594 \begin{cfa} 504 595 struct _pair_conc0 { 505 const char * first; 506 int second; 596 const char * first; int second; 507 597 }; 508 598 \end{cfa} … … 512 602 \begin{cfa} 513 603 struct _pair_conc1 { 514 void * first; 515 void * second; 604 void * first, * second; 516 605 }; 517 606 \end{cfa} … … 568 657 Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \newterm{tag-structures}. 569 658 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@{}} 570 662 \begin{cfa} 571 663 forall( dtype Unit ) struct scalar { unsigned long value; }; 572 664 struct metres {}; 573 665 struct litres {}; 574 575 666 forall( dtype U ) scalar(U) ?+?( scalar(U) a, scalar(U) b ) { 576 667 return (scalar(U)){ a.value + b.value }; 577 668 } 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} 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} 584 682 @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 @?+?@. 585 683 These implementations may even be separately compiled, unlike \CC template functions. … … 863 961 } 864 962 \end{cfa} 865 One more step permits the summation of any sum mable type with all arguments of the same type:866 \begin{cfa} 867 trait sum mable( otype T ) {963 One more step permits the summation of any sumable type with all arguments of the same type: 964 \begin{cfa} 965 trait sumable( otype T ) { 868 966 T ?+?( T, T ); 869 967 }; 870 forall( otype R | sum mable( R ) ) R sum( R x, R y ) {968 forall( otype R | sumable( R ) ) R sum( R x, R y ) { 871 969 return x + y; 872 970 } 873 forall( otype R, ttype Params | sum mable(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) {971 forall( otype R, ttype Params | sumable(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) { 874 972 return sum( x + y, rest ); 875 973 } … … 922 1020 \begin{cfa} 923 1021 forall( dtype T0, dtype T1 | sized(T0) | sized(T1) ) struct _tuple2 { 924 T0 field_0; $\C{// generated before the first 2-tuple}$ 925 T1 field_1; 1022 T0 field_0; T1 field_1; $\C{// generated before the first 2-tuple}$ 926 1023 }; 927 1024 _tuple2(int, int) f() { 928 1025 _tuple2(double, double) x; 929 1026 forall( dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2) ) struct _tuple3 { 930 T0 field_0; $\C{// generated before the first 3-tuple}$ 931 T1 field_1; 932 T2 field_2; 1027 T0 field_0; T1 field_1; T2 field_2; $\C{// generated before the first 3-tuple}$ 933 1028 }; 934 1029 _tuple3(int, double, int) y; 935 1030 } 936 1031 \end{cfa} 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}% 1032 Tuple expressions are then converted directly into compound literals, \eg @[5, 'x', 1.24]@ becomes @(_tuple3(int, char,@ @double)){ 5, 'x', 1.24 }@. 940 1033 941 1034 \begin{comment} … … 1022 1115 \lstDeleteShortInline@% 1023 1116 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1024 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1117 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 1025 1118 \begin{cfa} 1026 1119 case 2, 10, 34, 42: … … 1037 1130 \lstDeleteShortInline@% 1038 1131 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1039 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1132 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 1040 1133 \begin{cfa} 1041 1134 case 2~42: … … 1090 1183 \centering 1091 1184 \lstDeleteShortInline@% 1092 \begin{tabular}{@{}l @{\hspace{2\parindentlnth}}l@{}}1093 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1185 \begin{tabular}{@{}l|@{\hspace{\parindentlnth}}l@{}} 1186 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 1094 1187 \begin{cfa} 1095 1188 `choose` ( day ) { 1096 1189 case Mon~Thu: // program 1097 1190 1098 case Fri: // program1191 case Fri: // program 1099 1192 wallet += pay; 1100 1193 `fallthrough;` 1101 case Sat: // party1194 case Sat: // party 1102 1195 wallet -= party; 1103 1196 1104 1197 case Sun: // rest 1105 1198 1106 default: //error1199 default: // print error 1107 1200 } 1108 1201 \end{cfa} … … 1112 1205 case Mon: case Tue: case Wed: case Thu: // program 1113 1206 `break;` 1114 case Fri: // program1207 case Fri: // program 1115 1208 wallet += pay; 1116 1209 1117 case Sat: // party1210 case Sat: // party 1118 1211 wallet -= party; 1119 1212 `break;` 1120 1213 case Sun: // rest 1121 1214 `break;` 1122 default: //error1215 default: // print error 1123 1216 } 1124 1217 \end{cfa} … … 1136 1229 \centering 1137 1230 \lstDeleteShortInline@% 1138 \begin{tabular}{@{}l @{\hspace{2\parindentlnth}}l@{}}1139 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{non-terminator}} & \multicolumn{1}{c}{\textbf{target label}} \\1231 \begin{tabular}{@{}l|@{\hspace{\parindentlnth}}l@{}} 1232 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{non-terminator}} & \multicolumn{1}{c@{}}{\textbf{target label}} \\ 1140 1233 \begin{cfa} 1141 1234 choose ( ... ) { … … 1180 1273 \begin{figure} 1181 1274 \lstDeleteShortInline@% 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}} \\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}} \\ 1184 1277 \begin{cfa} 1185 1278 `LC:` { … … 1189 1282 `LIF:` if ( ... ) { 1190 1283 `LF:` for ( ... ) { 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 1284 ... break `LC`; ... 1285 ... break `LS`; ... 1286 ... break `LIF`; ... 1287 ... continue `LF;` ... 1288 ... break `LF`; ... 1200 1289 } // for 1201 1290 } else { … … 1213 1302 if ( ... ) { 1214 1303 for ( ... ) { 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:` ; 1304 ... goto `LC`; ... 1305 ... goto `LS`; ... 1306 ... goto `LIF`; ... 1307 ... goto `LFC`; ... 1308 ... goto `LFB`; ... 1224 1309 `LFC:` ; } `LFB:` ; 1225 1310 } else { … … 1243 1328 // continue loop 1244 1329 // terminate loop 1245 // continue loop1246 // terminate loop1247 1330 1248 1331 1249 1332 1250 1333 // terminate if 1251 1252 1253 1334 1254 1335 \end{cfa} … … 1277 1358 \subsection{Exception Handling} 1278 1359 1279 The following framework for \CFA exception 1360 The following framework for \CFA exception-handling is in place, excluding some runtime type-information and virtual functions. 1280 1361 \CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling})~\cite{Buhr92b,Buhr00a}. 1281 1362 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. … … 1288 1369 \begin{cquote} 1289 1370 \lstDeleteShortInline@% 1290 \begin{tabular}{@{}l @{\hspace{2\parindentlnth}}l@{}}1291 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{Resumption}} & \multicolumn{1}{c}{\textbf{Termination}} \\1371 \begin{tabular}{@{}l|@{\hspace{\parindentlnth}}l@{}} 1372 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{Resumption}} & \multicolumn{1}{c@{}}{\textbf{Termination}} \\ 1292 1373 \begin{cfa} 1293 1374 `exception R { int fix; };` … … 1355 1436 resume( $\emph{alternate-stack}$ ) 1356 1437 \end{cfa} 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}.1438 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task~\cite{Delisle18}. 1358 1439 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. 1359 1440 … … 1405 1486 If an exception is raised and caught, the handler is run before the finally clause. 1406 1487 Like a destructor (see Section~\ref{s:ConstructorsDestructors}), a finally clause can raise an exception but not if there is an exception being propagated. 1407 Mimicking the @finally@ clause with mechanisms like RAII is non-trivial lywhen there are multiple types and local accesses.1488 Mimicking the @finally@ clause with mechanisms like RAII is non-trivial when there are multiple types and local accesses. 1408 1489 1409 1490 … … 1411 1492 \label{s:WithStatement} 1412 1493 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} 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; }; 1443 1501 struct T { double m, n; }; 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} 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. 1464 1522 1465 1523 In detail, the @with@ statement has the form: … … 1474 1532 The object is the implicit qualifier for the open structure-fields. 1475 1533 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. 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. 1478 1535 The difference between parallel and nesting occurs for fields with the same name and type: 1479 1536 \begin{cfa} … … 1482 1539 with ( s, t ) { 1483 1540 j + k; $\C{// unambiguous, s.j + t.k}$ 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}$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}$ 1488 1545 int c = s.i + t.i; $\C{// unambiguous, qualification}$ 1489 (double)m; $\C{// unambiguous, cast }$1546 (double)m; $\C{// unambiguous, cast s.m}$ 1490 1547 } 1491 1548 \end{cfa} … … 1511 1568 and implicitly opened \emph{after} a function-body open, to give them higher priority: 1512 1569 \begin{cfa} 1513 void ?{}( S & s, int `i` ) with ( s ) ` with( $\emph{\color{red}params}$ )` {1570 void ?{}( S & s, int `i` ) with ( s ) `{` `with( $\emph{\color{red}params}$ )` { 1514 1571 s.i = `i`; j = 3; m = 5.5; 1515 } 1572 } `}` 1516 1573 \end{cfa} 1517 1574 Finally, a cast may be used to disambiguate among overload variables in a @with@ expression: … … 1581 1638 \lstDeleteShortInline@% 1582 1639 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{}} 1583 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1640 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 1584 1641 \begin{cfa} 1585 1642 `[5] *` int x1; … … 1609 1666 \lstDeleteShortInline@% 1610 1667 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1611 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1668 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 1612 1669 \begin{cfa} 1613 1670 `*` int x, y; 1614 int y;1615 \end{cfa} 1616 & 1617 \begin{cfa} 1618 int `*`x, `*`y ;1671 int z; 1672 \end{cfa} 1673 & 1674 \begin{cfa} 1675 int `*`x, `*`y, z; 1619 1676 1620 1677 \end{cfa} … … 1622 1679 \lstMakeShortInline@% 1623 1680 \end{cquote} 1624 The downside of the \CFA semantics is the need to separate regular and pointer declarations. 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. 1625 1683 1626 1684 \begin{comment} … … 1629 1687 \lstDeleteShortInline@% 1630 1688 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{}} 1631 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{C}} \\1689 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{C}} \\ 1632 1690 \begin{cfa} 1633 1691 [ 5 ] int z; … … 1671 1729 \lstDeleteShortInline@% 1672 1730 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{}} 1673 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{C}} \\1731 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{C}} \\ 1674 1732 \begin{cfa} 1675 1733 extern const * const int x; … … 1696 1754 \lstDeleteShortInline@% 1697 1755 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1698 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1756 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 1699 1757 \begin{cfa} 1700 1758 y = (* int)x; … … 1724 1782 \lstDeleteShortInline@% 1725 1783 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 1726 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\1784 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 1727 1785 \begin{cfa} 1728 1786 [double] foo(), foo( int ), foo( double ) {...} … … 1742 1800 * [ * int ] ( int y ) gp; $\C{// pointer to function returning pointer to int with int parameter}$ 1743 1801 * [ ] ( int, char ) hp; $\C{// pointer to function returning no result with int and char parameters}$ 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} 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. 1750 1805 1751 1806 Finally, new \CFA declarations may appear together with C declarations in the same program block, but cannot be mixed within a specific declaration. … … 1804 1859 This provides a much more orthogonal design for library implementors, obviating the need for workarounds such as @std::reference_wrapper@. 1805 1860 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}1816 1861 Rebinding allows \CFA references to be default-initialized (\eg to a null pointer\footnote{ 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. 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. 1823 1863 Rebinding is accomplished by extending the existing syntax and semantics of the address-of operator in C. 1824 1864 … … 1832 1872 \begin{itemize} 1833 1873 \item 1834 if @R@ is an rvalue of type {@T &@$_1 \cdots$@ &@$_r$} where $r \ge 1$ references (@&@ symbols) th an @&R@ has type {@T `*`&@$_{\color{red}2} \cdots$@ &@$_{\color{red}r}$}, \\ \ie @T@ pointer with $r-1$ references (@&@ symbols).1874 if @R@ is an rvalue of type {@T &@$_1 \cdots$@ &@$_r$} where $r \ge 1$ references (@&@ symbols) then @&R@ has type {@T `*`&@$_{\color{red}2} \cdots$@ &@$_{\color{red}r}$}, \\ \ie @T@ pointer with $r-1$ references (@&@ symbols). 1835 1875 1836 1876 \item … … 1866 1906 \end{cfa} 1867 1907 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. 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.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. 1869 1909 1870 1910 … … 1880 1920 \begin{tabular}{@{}l@{\hspace{3em}}l|l@{}} 1881 1921 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{C Type Nesting}} & \multicolumn{1}{c|}{\textbf{C Implicit Hoisting}} & \multicolumn{1}{c}{\textbf{\CFA}} \\ 1882 \hline1883 1922 \begin{cfa} 1884 1923 struct S { … … 1960 1999 The symbol \lstinline+^+ is used for the destructor name because it was the last binary operator that could be used in a unary context.}. 1961 2000 The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@. 1962 Like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @?{}(x, ...)@ or @^{}(x, ...)@.2001 Like other \CFA operators, these names represent the syntax used to explicitly call the constructor or destructor, \eg @s{...}@ or @^s{...}@. 1963 2002 The constructor and destructor have return type @void@, and the first parameter is a reference to the object type to be constructed or destructed. 1964 2003 While the first parameter is informally called the @this@ parameter, as in object-oriented languages, any variable name may be used. 1965 Both constructors and destructors allow additional paramete s after the @this@ parameter for specifying values for initialization/de-initialization\footnote{2004 Both constructors and destructors allow additional parameters after the @this@ parameter for specifying values for initialization/de-initialization\footnote{ 1966 2005 Destruction parameters are useful for specifying storage-management actions, such as de-initialize but not deallocate.}. 1967 2006 \begin{cfa} 1968 struct VLA { int len, * data; }; 2007 struct VLA { int len, * data; }; $\C{// variable length array of integers}$ 1969 2008 void ?{}( VLA & vla ) with ( vla ) { len = 10; data = alloc( len ); } $\C{// default constructor}$ 1970 2009 void ^?{}( VLA & vla ) with ( vla ) { free( data ); } $\C{// destructor}$ 1971 2010 { 1972 VLA x; $\C{// implicit: ?\{\}( x );}$1973 } $\C{// implicit: ?\^{}\{\}( x );}$2011 VLA x; $\C{// implicit:\ \ x\{\};}$ 2012 } $\C{// implicit:\ \textasciicircum{}x\{\};}$ 1974 2013 \end{cfa} 1975 2014 @VLA@ is a \newterm{managed type}\footnote{ … … 1996 2035 appropriate care is taken to not recursively call the copy constructor when initializing the second parameter. 1997 2036 1998 \CFA constructors may be explicitly call , like Java, and destructors may be explicitly called, like \CC.2037 \CFA constructors may be explicitly called, like Java, and destructors may be explicitly called, like \CC. 1999 2038 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. 2000 While existing call syntax works for explicit calls to constructors and destructors, \CFA also provides a more concise \newterm{operator syntax} for both:2039 Like the other operators in \CFA, there is a concise syntax for constructor/destructor function calls: 2001 2040 \begin{cfa} 2002 2041 { 2003 2042 VLA x, y = { 20, 0x01 }, z = y; $\C{// z points to y}$ 2004 // ?{}( x ); ?{}( y, 20, 0x01 ); ?{}( z, y );2043 // x{}; y{ 20, 0x01 }; z{ z, y }; 2005 2044 ^x{}; $\C{// deallocate x}$ 2006 2045 x{}; $\C{// reallocate x}$ … … 2009 2048 y{ x }; $\C{// reallocate y, points to x}$ 2010 2049 x{}; $\C{// reallocate x, not pointing to y}$ 2011 // ^?{}(z); ^?{}(y); ^?{}(x);2050 // ^z{}; ^y{}; ^x{}; 2012 2051 } 2013 2052 \end{cfa} … … 2030 2069 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. 2031 2070 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. 2032 The same syntax can be used in a compound literal, \eg \lstinline|a = VLA`@`{ 0, 0x0 }|, to create a C-style literal.2071 The same syntax can be used in a compound literal, \eg \lstinline|a = (VLA)`@`{ 0, 0x0 }|, to create a C-style literal. 2033 2072 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. 2034 2073 … … 2046 2085 2047 2086 2087 \begin{comment} 2048 2088 \subsection{Integral Suffixes} 2049 2089 … … 2079 2119 \lstMakeShortInline@% 2080 2120 \end{cquote} 2121 \end{comment} 2081 2122 2082 2123 … … 2084 2125 2085 2126 In C, @0@ has the special property that it is the only ``false'' value; 2086 fromthe standard, any value that compares equal to @0@ is false, while any value that compares unequal to @0@ is true.2127 by the standard, any value that compares equal to @0@ is false, while any value that compares unequal to @0@ is true. 2087 2128 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. 2088 2129 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. … … 2119 2160 \lstDeleteShortInline@% 2120 2161 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{\hspace{2\parindentlnth}}l@{}} 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}} \\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}} \\ 2122 2163 \begin{cfa} 2123 2164 int |?`h|( int s ); … … 2164 2205 \lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}} 2165 2206 \lstDeleteShortInline@% 2166 \begin{tabular}{@{}l@{\hspace{ 2\parindentlnth}}l@{}}2167 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{\CC}} \\2207 \begin{tabular}{@{}l@{\hspace{1.25\parindentlnth}}l@{}} 2208 \multicolumn{1}{@{}c@{\hspace{1.25\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{\CC}} \\ 2168 2209 \begin{cfa} 2169 2210 struct W { … … 2209 2250 W w, heavy = { 20 }; 2210 2251 w = 155|_lb|; 2211 w = 0b1111|_lb|; // error,binary unsupported2252 // binary unsupported 2212 2253 w = 0${\color{red}\LstBasicStyle{'}}$233|_lb|; // quote separator 2213 2254 w = 0x9b|_kg|; … … 2239 2280 \lstDeleteShortInline@% 2240 2281 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2241 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c}{\textbf{Usage}} \\2282 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c@{}}{\textbf{Usage}} \\ 2242 2283 \begin{cfa} 2243 2284 const short int `MIN` = -32768; … … 2257 2298 \begin{cquote} 2258 2299 \lstDeleteShortInline@% 2259 \begin{tabular}{@{}l@{\hspace{ 2\parindentlnth}}l@{}}2260 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\2300 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{}} 2301 \multicolumn{1}{@{}c@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 2261 2302 \begin{cfa} 2262 2303 MIN … … 2267 2308 & 2268 2309 \begin{cfa} 2269 SCHAR_MIN,CHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN, FLT_MIN, DBL_MIN, LDBL_MIN2270 SCHAR_MAX,UCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX, FLT_MAX, DBL_MAX, LDBL_MAX2310 CHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN, FLT_MIN, DBL_MIN, LDBL_MIN 2311 UCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX, FLT_MAX, DBL_MAX, LDBL_MAX 2271 2312 M_PI, M_PIl 2272 2313 M_E, M_El … … 2284 2325 \lstDeleteShortInline@% 2285 2326 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2286 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c}{\textbf{Usage}} \\2327 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c@{}}{\textbf{Usage}} \\ 2287 2328 \begin{cfa} 2288 2329 float `log`( float x ); … … 2303 2344 \lstDeleteShortInline@% 2304 2345 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2305 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\2346 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 2306 2347 \begin{cfa} 2307 2348 log … … 2331 2372 \lstDeleteShortInline@% 2332 2373 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2333 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c}{\textbf{Usage}} \\2374 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{Definition}} & \multicolumn{1}{c@{}}{\textbf{Usage}} \\ 2334 2375 \begin{cfa} 2335 2376 unsigned int `abs`( int ); … … 2350 2391 \lstDeleteShortInline@% 2351 2392 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2352 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\2393 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 2353 2394 \begin{cfa} 2354 2395 abs … … 2373 2414 an allocation with a specified character. 2374 2415 \item[resize] 2375 an existing allocation to decrease d or increasedits size.2416 an existing allocation to decrease or increase its size. 2376 2417 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. 2377 2418 For an increase in storage size, new storage after the copied data may be filled. … … 2387 2428 2388 2429 \begin{table} 2430 \caption{Storage-Management Operations} 2431 \label{t:StorageManagementOperations} 2389 2432 \centering 2390 2433 \lstDeleteShortInline@% … … 2406 2449 \lstDeleteShortInline~% 2407 2450 \lstMakeShortInline@% 2408 \caption{Storage-Management Operations}2409 \label{t:StorageManagementOperations}2410 2451 \end{table} 2411 2452 2412 2453 \begin{figure} 2413 2454 \centering 2414 \begin{cquote} 2415 \begin{cfa}[aboveskip=0pt] 2455 \begin{cfa}[aboveskip=0pt,xleftmargin=0pt] 2416 2456 size_t dim = 10; $\C{// array dimension}$ 2417 2457 char fill = '\xff'; $\C{// initialization fill value}$ … … 2419 2459 \end{cfa} 2420 2460 \lstDeleteShortInline@% 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} 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] 2424 2464 ip = alloc(); 2425 2465 ip = alloc( fill ); … … 2436 2476 & 2437 2477 \begin{cfa} 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 ) ); 2449 \end{cfa} 2450 \end{tabular} 2451 \lstMakeShortInline@% 2452 \end{cquote} 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) ); 2489 \end{cfa} 2490 \end{tabular} 2491 \lstMakeShortInline@% 2453 2492 \caption{\CFA versus C Storage-Allocation} 2454 2493 \label{f:StorageAllocation} … … 2463 2502 S * as = anew( dim, 2, 3 ); $\C{// each array element initialized to 2, 3}$ 2464 2503 \end{cfa} 2465 Note, \CC can only initializ ationarray elements via the default constructor.2504 Note, \CC can only initialize array elements via the default constructor. 2466 2505 2467 2506 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. … … 2480 2519 \lstDeleteShortInline@% 2481 2520 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}} 2482 \multicolumn{1}{ c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{\CC}} \\2521 \multicolumn{1}{@{}c@{\hspace{2\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{\CC}} \\ 2483 2522 \begin{cfa} 2484 2523 int x = 1, y = 2, z = 3; … … 2535 2574 \end{cquote} 2536 2575 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. 2537 2576 \begin{comment} 2538 2577 The implicit separator character (space/blank) is a separator not a terminator. 2539 2578 The rules for implicitly adding the separator are: … … 2554 2593 }% 2555 2594 \end{itemize} 2595 \end{comment} 2556 2596 There are functions to set and get the separator string, and manipulators to toggle separation on and off in the middle of output. 2557 2597 … … 2568 2608 \centering 2569 2609 \lstDeleteShortInline@% 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}} \\2610 \begin{tabular}{@{}l@{\hspace{3\parindentlnth}}l@{}} 2611 \multicolumn{1}{@{}c@{\hspace{3\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\ 2572 2612 \begin{cfa} 2573 2613 #include <gmp> … … 2602 2642 2603 2643 2604 \section{ Evaluation}2644 \section{Polymorphism Evaluation} 2605 2645 \label{sec:eval} 2606 2646 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}). 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}). 2610 2653 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. 2611 2654 A more illustrative comparison measures the costs of idiomatic usage of each language's features. … … 2638 2681 \end{figure} 2639 2682 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.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. 2641 2684 The \CCV variant illustrates an alternative object-oriented idiom where all objects inherit from a base @object@ class, mimicking a Java-like interface; 2642 2685 hence runtime checks are necessary to safely down-cast objects. 2643 2686 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. 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.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. 2645 2688 2646 2689 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. 2647 2690 The graph plots the median of 5 consecutive runs of each program, with an initial warm-up run omitted. 2648 All code is compiled at \texttt{-O2} by gcc or g++ 6. 3.0, with all \CC code compiled as \CCfourteen.2691 All code is compiled at \texttt{-O2} by gcc or g++ 6.4.0, with all \CC code compiled as \CCfourteen. 2649 2692 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. 2650 2693 … … 2657 2700 2658 2701 \begin{table} 2659 \centering2660 2702 \caption{Properties of benchmark code} 2661 2703 \label{tab:eval} 2704 \centering 2662 2705 \newcommand{\CT}[1]{\multicolumn{1}{c}{#1}} 2663 2706 \begin{tabular}{rrrrr} 2664 2707 & \CT{C} & \CT{\CFA} & \CT{\CC} & \CT{\CCV} \\ \hline 2665 2708 maximum memory usage (MB) & 10,001 & 2,502 & 2,503 & 11,253 \\ 2666 source code size (lines) & 196 & 186 & 125 & 290\\2709 source code size (lines) & 201 & 191 & 125 & 294 \\ 2667 2710 redundant type annotations (lines) & 27 & 0 & 2 & 16 \\ 2668 2711 binary size (KB) & 14 & 257 & 14 & 37 \\ … … 2672 2715 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; 2673 2716 this inefficiency is exacerbated by the second level of generic types in the pair benchmarks. 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.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. 2675 2718 \CCV is slower than C largely due to the cost of runtime type-checking of down-casts (implemented with @dynamic_cast@); 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. 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. 2678 2722 Finally, the binary size for \CFA is larger because of static linking with the \CFA libraries. 2679 2723 … … 2687 2731 Line-count is a fairly rough measure of code complexity; 2688 2732 another important factor is how much type information the programmer must specify manually, especially where that information is not compiler-checked. 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 un type-checked downcasts, \eg @object@ to @integer@ when popping a stack.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. 2690 2734 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. 2691 2735 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. 2692 2736 The \CFA benchmark is able to eliminate all redundant type annotations through use of the polymorphic @alloc@ function discussed in Section~\ref{sec:libraries}. 2693 2737 2738 We conjecture these results scale across most generic data-types as the underlying polymorphism implement is constant. 2739 2694 2740 2695 2741 \section{Related Work} … … 2697 2743 2698 2744 \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. 2699 2752 2700 2753 \CC provides three disjoint polymorphic extensions to C: overloading, inheritance, and templates. … … 2750 2803 Go does not have tuples but supports MRVF. 2751 2804 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. 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.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. 2753 2806 2754 2807 … … 2767 2820 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}. 2768 2821 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/destructors2786 2787 0/1 Literals \\2788 user defined: D, Objective-C2789 \end{comment}2790 2822 2791 2823 … … 2802 2834 Finally, we demonstrate that \CFA performance for some idiomatic cases is better than C and close to \CC, showing the design is practically applicable. 2803 2835 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. 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. 2810 2840 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). 2811 2841 These approaches are not mutually exclusive and allow performance optimizations to be applied only when necessary, without suffering global code-bloat. … … 2816 2846 2817 2847 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. 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 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% 2821 2852 \bibliography{pl} 2822 2853 }% 2823 2854 2824 2855 \appendix 2825 2856 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 { 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 { 2835 2870 void * value; 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 ); 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 ); 2845 2892 } 2846 2893 s->head = NULL; 2847 2894 } 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 * ) ) { 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 * ) ) { 2860 2904 if ( s->head == t->head ) return s; 2861 2905 clear_stack( s, free_el ); /***/ … … 2863 2907 return s; 2864 2908 } 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 }; /***/ 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 }; /***/ 2869 2915 s->head = n; 2870 2916 } 2871 void * pop_stack( st ruct stack * s ) {2872 struct stack_node * n = s->head;2917 void * pop_stack( stack * s ) { 2918 node * n = s->head; 2873 2919 s->head = n->next; 2874 2920 void * v = n->value; … … 2877 2923 } 2878 2924 \end{cfa} 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); 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] 2937 forall( otype T ) { 2938 struct node { 2939 T value; 2940 node(T) * next; 2941 }; 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; 2894 2951 } 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}2931 forall( otype T ) {2932 struct stack_node {2933 T value;2934 stack_node(T) * next;2935 };2936 struct stack { stack_node(T) * head; };2937 2952 void clear( stack(T) & s ) with( s ) { 2938 for ( stack_node(T) * next = head; next; ) {2939 stack_node(T) * crnt = next;2940 n ext = crnt->next;2941 ^(*cr nt){};2942 free( crnt);2953 for ( node(T) * nx = head; nx; ) { 2954 node(T) * cr = nx; 2955 nx = cr->next; 2956 ^(*cr){}; 2957 free( cr ); 2943 2958 } 2944 2959 head = 0; 2945 2960 } 2961 2962 \end{cfa} 2963 & 2964 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 2946 2965 void ?{}( stack(T) & s ) { (s.head){ 0 }; } 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 } 2966 void ^?{}( stack(T) & s) { clear( s ); } 2956 2967 stack(T) ?=?( stack(T) & s, stack(T) t ) { 2957 2968 if ( s.head == t.head ) return s; … … 2960 2971 return s; 2961 2972 } 2962 void ^?{}( stack(T) & s) { clear( s ); } 2963 _Bool empty( const stack(T) & s ) { return s.head == 0; } 2973 _Bool empty( const stack(T) & s ) { 2974 return s.head == 0; 2975 } 2964 2976 void push( stack(T) & s, T value ) with( s ) { 2965 stack_node(T) * n = alloc();2977 node(T) * n = alloc(); 2966 2978 (*n){ value, head }; 2967 2979 head = n; 2968 2980 } 2969 2981 T pop( stack(T) & s ) with( s ) { 2970 stack_node(T) * n = head;2982 node(T) * n = head; 2971 2983 head = n->next; 2972 2984 T v = n->value; … … 2976 2988 } 2977 2989 } 2978 \end{comment} 2979 2980 \medskip\noindent 2981 \CC 2982 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 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] 2983 3002 template<typename T> struct stack { 2984 3003 struct node { 2985 3004 T value; 2986 3005 node * next; 2987 node( const T & v, node * n = nullptr ) : value( v ), next( n ) {} 3006 node( const T & v, node * n = nullptr ) : 3007 value( v ), next( n ) {} 2988 3008 }; 2989 3009 node * head; 2990 stack() : head( nullptr ) {} 2991 stack( const stack<T> & o ) { copy( o ); } 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 } 2992 3018 void clear() { 2993 for ( node * n ext = head; next; ) {2994 node * cr nt = next;2995 n ext = crnt->next;2996 delete cr nt;3019 for ( node * nx = head; nx; ) { 3020 node * cr = nx; 3021 nx = cr->next; 3022 delete cr; 2997 3023 } 2998 3024 head = nullptr; 2999 3025 } 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 } 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 ); } 3008 3031 ~stack() { clear(); } 3009 stack & operator= 3032 stack & operator=( const stack<T> & o ) { 3010 3033 if ( this == &o ) return *this; 3011 3034 clear(); … … 3013 3036 return *this; 3014 3037 } 3015 bool empty() const { return head == nullptr; } 3016 void push( const T & value ) { head = new node{ value, head }; /***/ } 3038 bool empty() const { 3039 return head == nullptr; 3040 } 3041 void push( const T & value ) { 3042 head = new node{ value, head }; /***/ 3043 } 3017 3044 T pop() { 3018 3045 node * n = head; … … 3023 3050 } 3024 3051 }; 3025 \end{cfa} 3026 3027 \medskip\noindent 3028 \CCV 3029 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 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] 3030 3065 struct stack { 3031 3066 struct node { 3032 3067 ptr<object> value; 3033 3068 node * next; 3034 node( const object & v, node * n = nullptr ) : value( v.new_copy() ), next( n ) {} 3069 node( const object & v, node * n = nullptr ) : 3070 value( v.new_copy() ), next( n ) {} 3035 3071 }; 3036 3072 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 } 3037 3081 void clear() { 3038 for ( node * n ext = head; next; ) {3039 node * cr nt = next;3040 n ext = crnt->next;3041 delete cr nt;3082 for ( node * nx = head; nx; ) { 3083 node * cr = nx; 3084 nx = cr->next; 3085 delete cr; 3042 3086 } 3043 3087 head = nullptr; 3044 3088 } 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 } 3089 \end{cfa} 3090 & 3091 \begin{cfa}[xleftmargin=0pt,aboveskip=0pt,belowskip=0pt] 3053 3092 stack() : head( nullptr ) {} 3054 3093 stack( const stack & o ) { copy( o ); } 3055 3094 ~stack() { clear(); } 3056 stack & operator= 3095 stack & operator=( const stack & o ) { 3057 3096 if ( this == &o ) return *this; 3058 3097 clear(); … … 3060 3099 return *this; 3061 3100 } 3062 bool empty() const { return head == nullptr; } 3063 void push( const object & value ) { head = new node{ value, head }; /***/ } 3101 bool empty() const { 3102 return head == nullptr; 3103 } 3104 void push( const object & value ) { 3105 head = new node{ value, head }; /***/ 3106 } 3064 3107 ptr<object> pop() { 3065 3108 node * n = head; … … 3070 3113 } 3071 3114 }; 3072 \end{cfa} 3115 3116 \end{cfa} 3117 \end{tabular} 3118 \lstMakeShortInline@% 3119 \end{flushleft} 3073 3120 3074 3121 -
doc/papers/general/evaluation/c-bench.c
rf6f0cca3 rff29f08 5 5 #include "c-stack.h" 6 6 7 char * new_char( char c ) {8 char* q = malloc( sizeof(char)); /***/7 char * new_char( char c ) { 8 char* q = malloc( sizeof(char) ); /***/ 9 9 *q = c; 10 10 return q; 11 11 } 12 12 13 short * new_short( short s ) {14 short* q = malloc( sizeof(short)); /***/13 short * new_short( short s ) { 14 short* q = malloc( sizeof(short) ); /***/ 15 15 *q = s; 16 16 return q; … … 18 18 19 19 int* new_int( int i ) { 20 int* q = malloc( sizeof(int)); /***/20 int* q = malloc( sizeof(int) ); /***/ 21 21 *q = i; 22 22 return q; 23 23 } 24 24 25 void * copy_char( const void* p ) { return new_char( *(const char*)p ); } /***/26 void * copy_short( const void* p ) { return new_short( *(const short*)p ); } /***/27 void * copy_int( const void* p ) { return new_int( *(const int*)p ); } /***/28 void * copy_pair_short_char( const void* p ) { return copy_pair( p, copy_short, copy_char ); } /***/29 void free_pair_short_char( void * p ) { free_pair( p, free, free ); } /***/25 void * copy_char( const void * p ) { return new_char( *(const char*)p ); } /***/ 26 void * copy_short( const void * p ) { return new_short( *(const short*)p ); } /***/ 27 void * copy_int( const void * p ) { return new_int( *(const int*)p ); } /***/ 28 void * copy_pair_short_char( const void * p ) { return copy_pair( p, copy_short, copy_char ); } /***/ 29 void free_pair_short_char( void * p ) { free_pair( p, free, free ); } /***/ 30 30 31 31 int cmp_char( const void* a, const void* b ) { /***/ … … 37 37 } 38 38 39 int main(int argc, char ** argv) {39 int main(int argc, char * argv[] ) { 40 40 int maxi = 0, vali = 42; 41 41 struct stack si = new_stack(), ti; -
doc/papers/general/evaluation/c-pair.c
rf6f0cca3 rff29f08 2 2 #include "c-pair.h" 3 3 4 struct pair* new_pair(void* first, void* second) {5 struct pair* p = malloc(sizeof(struct pair)); /***/6 *p = ( structpair){ first, second }; /***/4 pair * new_pair( void * first, void * second ) { 5 pair * p = malloc( sizeof(pair) ); /***/ 6 *p = (pair){ first, second }; /***/ 7 7 return p; 8 8 } 9 9 10 struct pair* copy_pair(const struct pair* src,11 void * (*copy_first)(const void*), void* (*copy_second)(const void*)) {10 pair * copy_pair( const pair * src, 11 void * (* copy_first)(const void* ), void * (* copy_second)(const void *)) { 12 12 return new_pair( copy_first(src->first), copy_second(src->second) ); 13 13 } 14 14 15 void free_pair( struct pair* p, void (*free_first)(void*), void (*free_second)(void*)) {16 free_first( p->first);17 free_second( p->second);18 free( p);15 void free_pair( pair * p, void (* free_first)(void *), void (* free_second)(void *)) { 16 free_first( p->first ); 17 free_second( p->second ); 18 free( p ); 19 19 } 20 20 21 int cmp_pair( const struct pair* a, const struct pair* b,22 int (* cmp_first)(const void*, const void*), int (*cmp_second)(const void*, const void*)) {23 int c = cmp_first( a->first, b->first);24 if ( c == 0 ) c = cmp_second( a->second, b->second);21 int cmp_pair( const pair * a, const pair * b, 22 int (* cmp_first)(const void *, const void *), int (* cmp_second)(const void *, const void *)) { 23 int c = cmp_first( a->first, b->first ); 24 if ( c == 0 ) c = cmp_second( a->second, b->second ); 25 25 return c; 26 26 } -
doc/papers/general/evaluation/c-pair.h
rf6f0cca3 rff29f08 1 1 #pragma once 2 2 3 struct pair {4 void * first;5 void * second;6 } ;3 typedef struct pair { 4 void * first; 5 void * second; 6 } pair; 7 7 8 struct pair* new_pair(void* first, void* second);8 pair * new_pair( void * first, void * second ); 9 9 10 struct pair* copy_pair(const struct pair* src,11 void * (*copy_first)(const void*), void* (*copy_second)(const void*));10 pair * copy_pair( const pair * src, 11 void * (* copy_first)(const void *), void * (* copy_second)(const void *)); 12 12 13 void free_pair( struct pair* p, void (*free_first)(void*), void (*free_second)(void*));13 void free_pair( pair * p, void (* free_first)(void *), void (* free_second)(void *)); 14 14 15 int cmp_pair( const struct pair* a, const struct pair* b,16 int (* cmp_first)(const void*, const void*), int (*cmp_second)(const void*, const void*));15 int cmp_pair( const pair * a, const pair * b, 16 int (* cmp_first)(const void *, const void *), int (* cmp_second)(const void *, const void *)); -
doc/papers/general/evaluation/c-print.c
rf6f0cca3 rff29f08 4 4 #include "c-print.h" 5 5 6 void print_string( FILE* out, const char* x) { fprintf(out, "%s", x); }6 void print_string( FILE * out, const char * x ) { fprintf( out, "%s", x ); } 7 7 8 void print_bool( FILE* out, _Bool x) { fprintf(out, "%s", x ? "true" : "false"); }8 void print_bool( FILE * out, _Bool x ) { fprintf( out, "%s", x ? "true" : "false" ); } 9 9 10 void print_char( FILE* out, char x) {11 if ( 0x20 <= x && x <= 0x7E ) { fprintf( out, "'%c'", x); }12 else { fprintf( out, "'\\%x'", x); }10 void print_char( FILE * out, char x ) { 11 if ( 0x20 <= x && x <= 0x7E ) { fprintf( out, "'%c'", x ); } 12 else { fprintf( out, "'\\%x'", x ); } 13 13 } 14 14 15 void print_int( FILE* out, int x) { fprintf(out, "%d", x); }15 void print_int( FILE * out, int x ) { fprintf( out, "%d", x ); } 16 16 17 void print_fmt( FILE* out, char fmt, void* p) {17 void print_fmt( FILE * out, char fmt, void * p ) { 18 18 switch( fmt ) { 19 case 's': print_string( out, (const char*)p); break; /***/20 case 'b': print_bool( out, *(_Bool*)p); break; /***/21 case 'c': print_char( out, *(char*)p); break; /***/22 case 'd': print_int( out, *(int*)p); break; /***/19 case 's': print_string( out, (const char*)p ); break; /***/ 20 case 'b': print_bool( out, *(_Bool*)p ); break; /***/ 21 case 'c': print_char( out, *(char*)p ); break; /***/ 22 case 'd': print_int( out, *(int*)p ); break; /***/ 23 23 } 24 24 } 25 25 26 void print( FILE* out, const char* fmt, ...) {26 void print( FILE * out, const char * fmt, ... ) { 27 27 va_list args; 28 28 va_start(args, fmt); 29 for ( const char* it = fmt; *it; ++it) {29 for ( const char * it = fmt; *it; ++it ) { 30 30 switch( *it ) { 31 case 's': print_string( out, va_arg(args, const char*)); break; /***/32 case 'b': print_bool( out, va_arg(args, int)); break; /***/33 case 'c': print_char( out, va_arg(args, int)); break; /***/34 case 'd': print_int( out, va_arg(args, int)); break; /***/31 case 's': print_string( out, va_arg( args, const char * ) ); break; /***/ 32 case 'b': print_bool( out, va_arg( args, int ) ); break; /***/ 33 case 'c': print_char( out, va_arg( args, int ) ); break; /***/ 34 case 'd': print_int( out, va_arg( args, int ) ); break; /***/ 35 35 case 'p': { 36 const struct pair x = va_arg( args, const struct pair); /***/37 fprintf( out, "[");38 print_fmt( out, *++it, x.first); /***/39 fprintf( out, ", ");40 print_fmt( out, *++it, x.second); /***/41 fprintf( out, "]");36 const struct pair x = va_arg( args, const struct pair ); /***/ 37 fprintf( out, "[" ); 38 print_fmt( out, *++it, x.first ); /***/ 39 fprintf( out, ", " ); 40 print_fmt( out, *++it, x.second ); /***/ 41 fprintf( out, "]" ); 42 42 break; 43 43 } 44 44 } 45 45 } 46 va_end( args);46 va_end( args ); 47 47 } -
doc/papers/general/evaluation/c-print.h
rf6f0cca3 rff29f08 2 2 #include <stdio.h> 3 3 4 void print_string( FILE* out, const char* x);5 void print_bool( FILE* out, _Bool x);6 void print_char( FILE* out, char x);7 void print_int( FILE* out, int x);4 void print_string( FILE * out, const char * x ); 5 void print_bool( FILE * out, _Bool x ); 6 void print_char( FILE * out, char x ); 7 void print_int( FILE * out, int x ); 8 8 9 void print( FILE* out, const char* fmt, ...);9 void print( FILE * out, const char * fmt, ... ); -
doc/papers/general/evaluation/c-stack.c
rf6f0cca3 rff29f08 2 2 #include "c-stack.h" 3 3 4 struct stack_node {4 typedef struct node { 5 5 void * value; 6 struct stack_node * next;7 } ;6 struct node * next; 7 } node; 8 8 9 void clear_stack( struct stack * s, void (*free_el)( void * ) ) { 10 for ( struct stack_node * next = s->head; next; ) { 11 struct stack_node * crnt = next; 12 next = crnt->next; 13 free_el( crnt->value ); 14 free( crnt ); 9 void copy_stack( stack * s, const stack * t, void * (*copy)( const void * ) ) { 10 node ** cr = &s->head; 11 for ( node * nx = t->head; nx; nx = nx->next ) { 12 *cr = malloc( sizeof(node) ); /***/ 13 (*cr)->value = copy( nx->value ); 14 cr = &(*cr)->next; 15 } 16 *cr = NULL; 17 } 18 19 void clear_stack( stack * s, void (* free_el)( void * ) ) { 20 for ( node * nx = s->head; nx; ) { 21 node * cr = nx; 22 nx = cr->next; 23 free_el( cr->value ); 24 free( cr ); 15 25 } 16 26 s->head = NULL; 17 27 } 18 28 19 struct stack new_stack() { return (struct stack){ NULL }; /***/ } 29 stack new_stack() { 30 return (stack){ NULL }; /***/ 31 } 20 32 21 void copy_stack( struct stack * s, const struct stack * t, void * (*copy)( const void * ) ) { 22 struct stack_node ** crnt = &s->head; 23 for ( struct stack_node * next = t->head; next; next = next->next ) { 24 *crnt = malloc( sizeof(struct stack_node) ); /***/ 25 (*crnt)->value = copy( next->value ); 26 crnt = &(*crnt)->next; 27 } 28 *crnt = NULL; 29 } 30 struct stack * assign_stack( struct stack * s, const struct stack * t, 33 stack * assign_stack( stack * s, const stack * t, 31 34 void * (*copy_el)( const void * ), void (*free_el)( void * ) ) { 32 35 if ( s->head == t->head ) return s; … … 36 39 } 37 40 38 _Bool stack_empty( const struct stack * s ) { return s->head == NULL; } 41 _Bool stack_empty( const stack * s ) { 42 return s->head == NULL; 43 } 39 44 40 void push_stack( st ruct stack * s, void * v ) {41 struct stack_node * n = malloc( sizeof(struct stack_node) ); /***/42 *n = ( struct stack_node){ v, s->head }; /***/45 void push_stack( stack * s, void * v ) { 46 node * n = malloc( sizeof(node) ); /***/ 47 *n = (node){ v, s->head }; /***/ 43 48 s->head = n; 44 49 } 45 50 46 void * pop_stack( st ruct stack * s ) {47 struct stack_node * n = s->head;51 void * pop_stack( stack * s ) { 52 node * n = s->head; 48 53 s->head = n->next; 49 54 void * v = n->value; -
doc/papers/general/evaluation/c-stack.h
rf6f0cca3 rff29f08 1 1 #pragma once 2 2 3 struct stack_node;4 struct stack {5 struct stack_node* head;6 } ;3 struct node; 4 typedef struct stack { 5 struct node * head; 6 } stack; 7 7 8 struct stack new_stack();9 void c opy_stack(struct stack* dst, const struct stack* src, void* (*copy)(const void*));10 st ruct stack* assign_stack(struct stack* dst, const struct stack* src,11 void* (*copy_el)(const void*), void (*free_el)(void*)); 12 void clear_stack(struct stack* s, void (*free_el)(void*));8 void copy_stack(stack * dst, const stack * src, void * (* copy)(const void *)); 9 void clear_stack(stack * s, void (*free_el)(void *)); 10 stack new_stack(); 11 stack * assign_stack( stack * dst, const stack * src, 12 void * (* copy_el)(const void *), void (* free_el)(void *)); 13 13 14 _Bool stack_empty( const struct stack* s);15 void push_stack( struct stack* s, void* value);16 void * pop_stack(struct stack* s);14 _Bool stack_empty( const stack * s ); 15 void push_stack( stack * s, void * value ); 16 void * pop_stack( stack * s ); -
doc/papers/general/evaluation/cfa-stack.c
rf6f0cca3 rff29f08 2 2 #include "cfa-stack.h" 3 3 4 forall( otype T ) struct stack_node { 5 T value; 6 stack_node(T) * next; 7 }; 4 forall( otype T ) { 5 struct node { 6 T value; 7 node(T) * next; 8 }; 8 9 9 forall( otype T ) void clear( stack(T) & s ) with( s ) { 10 for ( stack_node(T) * next = head; next; ) { 11 stack_node(T) * crnt = next; 12 next = crnt->next; 13 ^(*crnt){}; 14 free(crnt); 10 void ?{}( stack(T) & s, stack(T) t ) { // copy 11 node(T) ** cr = &s.head; 12 for ( node(T) * nx = t.head; nx; nx = nx->next ) { 13 *cr = alloc(); 14 ((*cr)->value){ nx->value }; 15 cr = &(*cr)->next; 16 } 17 *cr = 0; 15 18 } 16 head = 0; 19 20 void clear( stack(T) & s ) with( s ) { 21 for ( node(T) * nx = head; nx; ) { 22 node(T) * cr = nx; 23 nx = cr->next; 24 ^(*cr){}; 25 free( cr ); 26 } 27 head = 0; 28 } 29 30 void ?{}( stack(T) & s ) { (s.head){ 0 }; } 31 void ^?{}( stack(T) & s) { clear( s ); } 32 33 stack(T) ?=?( stack(T) & s, stack(T) t ) { 34 if ( s.head == t.head ) return s; 35 clear( s ); 36 s{ t }; 37 return s; 38 } 39 40 _Bool empty( const stack(T) & s ) { 41 return s.head == 0; 42 } 43 44 void push( stack(T) & s, T value ) with( s ) { 45 node(T) * n = alloc(); 46 (*n){ value, head }; 47 head = n; 48 } 49 50 T pop( stack(T) & s ) with( s ) { 51 node(T) * n = head; 52 head = n->next; 53 T v = n->value; 54 ^(*n){}; 55 free( n ); 56 return v; 57 } 17 58 } 18 19 forall( otype T ) void ?{}( stack(T) & s ) { (s.head){ 0 }; }20 21 forall( otype T ) void ?{}( stack(T) & s, stack(T) t ) {22 stack_node(T) ** crnt = &s.head;23 for ( stack_node(T) * next = t.head; next; next = next->next ) {24 *crnt = alloc();25 ((*crnt)->value){ next->value };26 crnt = &(*crnt)->next;27 }28 *crnt = 0;29 }30 31 forall( otype T ) stack(T) ?=?( stack(T) & s, stack(T) t ) {32 if ( s.head == t.head ) return s;33 clear( s );34 s{ t };35 return s;36 }37 38 forall( otype T ) void ^?{}( stack(T) & s) { clear( s ); }39 40 forall( otype T ) _Bool empty( const stack(T) & s ) { return s.head == 0; }41 42 forall( otype T ) void push( stack(T) & s, T value ) with( s ) {43 stack_node(T) * n = alloc();44 (*n){ value, head };45 head = n;46 }47 48 forall( otype T ) T pop( stack(T) & s ) with( s ) {49 stack_node(T) * n = head;50 head = n->next;51 T v = n->value;52 ^(*n){};53 free( n );54 return v;55 } -
doc/papers/general/evaluation/cfa-stack.h
rf6f0cca3 rff29f08 1 1 #pragma once 2 2 3 forall( otype T ) struct stack_node; 4 forall( otype T ) struct stack { 5 stack_node(T) * head; 6 }; 3 forall( otype T ) { 4 struct node; 5 struct stack { 6 node(T) * head; 7 }; 7 8 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);9 void ?{}( stack(T) & s, stack(T) t ); 10 void clear( stack(T) & s ); 11 void ?{}( stack(T) & s ); 12 void ^?{}( stack(T) & s); 12 13 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 ); 14 stack(T) ?=?( stack(T) & s, stack(T) t ); 15 _Bool empty( const stack(T) & s ); 16 void push( stack(T) & s, T value ); 17 T pop( stack(T) & s ); 18 } -
doc/papers/general/evaluation/cpp-stack.hpp
rf6f0cca3 rff29f08 10 10 node * head; 11 11 12 stack() : head( nullptr ) {} 13 stack( const stack<T> & o ) { copy( o ); } 12 void copy( const stack<T> & o ) { 13 node ** cr = &head; 14 for ( node * nx = o.head; nx; nx = nx->next ) { 15 *cr = new node{ nx->value }; /***/ 16 cr = &(*cr)->next; 17 } 18 *cr = nullptr; 19 } 14 20 15 21 void clear() { 16 for ( node * n ext = head; next; ) {17 node * cr nt = next;18 n ext = crnt->next;19 delete cr nt;22 for ( node * nx = head; nx; ) { 23 node * cr = nx; 24 nx = cr->next; 25 delete cr; 20 26 } 21 27 head = nullptr; 22 28 } 23 29 24 void copy( const stack<T> & o ) { 25 node ** crnt = &head; 26 for ( node * next = o.head; next; next = next->next ) { 27 *crnt = new node{ next->value }; /***/ 28 crnt = &(*crnt)->next; 29 } 30 *crnt = nullptr; 31 } 32 30 stack() : head( nullptr ) {} 31 stack( const stack<T> & o ) { copy( o ); } 33 32 ~stack() { clear(); } 34 33 35 stack & operator= 34 stack & operator=( const stack<T> & o ) { 36 35 if ( this == &o ) return *this; 37 36 clear(); … … 40 39 } 41 40 42 bool empty() const { return head == nullptr; } 41 bool empty() const { 42 return head == nullptr; 43 } 43 44 44 void push( const T & value ) { head = new node{ value, head }; /***/ } 45 void push( const T & value ) { 46 head = new node{ value, head }; /***/ 47 } 45 48 46 49 T pop() { -
doc/papers/general/evaluation/cpp-vstack.cpp
rf6f0cca3 rff29f08 4 4 stack::node::node( const object & v, node * n ) : value( v.new_copy() ), next( n ) {} 5 5 6 void stack::copy( const stack & o ) { 7 node ** cr = &head; 8 for ( node * nx = o.head; nx; nx = nx->next ) { 9 *cr = new node{ *nx->value }; /***/ 10 cr = &(*cr)->next; 11 } 12 *cr = nullptr; 13 } 14 6 15 void stack::clear() { 7 for ( node * n ext = head; next; ) {8 node * cr nt = next;9 n ext = crnt->next;10 delete cr nt;16 for ( node * nx = head; nx; ) { 17 node * cr = nx; 18 nx = cr->next; 19 delete cr; 11 20 } 12 21 head = nullptr; 13 }14 15 void stack::copy( const stack & o ) {16 node ** crnt = &head;17 for ( node * next = o.head; next; next = next->next ) {18 *crnt = new node{ *next->value }; /***/19 crnt = &(*crnt)->next;20 }21 *crnt = nullptr;22 22 } 23 23 … … 33 33 } 34 34 35 bool stack::empty() const { return head == nullptr; } 35 bool stack::empty() const { 36 return head == nullptr; 37 } 36 38 37 void stack::push( const object & value ) { head = new node{ value, head }; /***/ } 39 void stack::push( const object & value ) { 40 head = new node{ value, head }; /***/ 41 } 38 42 39 43 ptr<object> stack::pop() { -
doc/papers/general/evaluation/cpp-vstack.hpp
rf6f0cca3 rff29f08 10 10 node * head; 11 11 12 void copy( const stack & o ); 12 13 void clear(); 13 void copy( const stack & o );14 14 15 15 stack(); -
doc/papers/general/evaluation/timing.dat
rf6f0cca3 rff29f08 1 1 "400 million repetitions" "C" "\\CFA{}" "\\CC{}" "\\CC{obj}" 2 "push\nint" 3002 2459 1542 3269 3 "copy\nint" 2985 2057 1539 3083 4 "clear\nint" 1374 827 756 1469 5 "pop\nint" 1416 1221 760 5098 6 "push\npair" 4214 2752 950 6873 7 "copy\npair" 6127 2105 987 7293 8 "clear\npair" 2881 885 751 3460 9 "pop\npair" 3046 5434 822 24962 2 "push\nint" 2911 2034 1504 3246 3 "copy\nint" 2953 1622 1526 3075 4 "clear\nint" 1397 754 753 1452 5 "pop\nint" 1446 1203 760 5016 6 "push\npair" 3673 2297 955 6971 7 "copy\npair" 6027 1183 998 7204 8 "clear\npair" 2840 773 748 3511 9 "pop\npair" 3025 5414 813 23867 10 -
doc/papers/general/evaluation/timing.gp
rf6f0cca3 rff29f08 24 24 set yrange [0:10] 25 25 26 set label "2 5.0" at 7.125,10.527 26 set label "23.9" at 7.125,10.5 27 set style fill pattern 4 border lt -1 28 28 # set datafile separator "," 29 29 plot for [COL=2:5] 'evaluation/timing.dat' using (column(COL)/SCALE):xticlabels(1) title columnheader
Note:
See TracChangeset
for help on using the changeset viewer.