Changes in / [4c11fce:5600747]


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/papers/general/Paper.tex

    r4c11fce r5600747  
    267267int m = max( max, -max );                                       $\C{// uses (3) and (1) twice, by matching return type}$
    268268\end{cfa}
    269 
    270269\CFA maximizes the ability to reuse names to aggressively address the naming problem.
    271270In some cases, hundreds of names can be reduced to tens, resulting in a significant cognitive reduction.
     
    286285
    287286
    288 \subsection{\texorpdfstring{\protect\lstinline{forall} Functions}{forall Functions}}
     287\subsection{\texorpdfstring{\LstKeywordStyle{forall} Functions}{forall Functions}}
    289288\label{sec:poly-fns}
    290289
     
    436435One approach is to write bespoke data-structures for each context in which they are needed.
    437436While this approach is flexible and supports integration with the C type-checker and tooling, it is also tedious and error-prone, especially for more complex data structures.
    438 A second approach is to use @void *@ based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allow reuse of code with common functionality.
     437A second approach is to use @void *@--based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allow reuse of code with common functionality.
    439438However, basing all polymorphism on @void *@ eliminates the type-checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is not otherwise needed.
    440439A third approach to generic code is to use preprocessor macros, which does allow the generated code to be both generic and type-checked, but errors may be difficult to interpret.
     
    509508If a dynamic generic-type is declared to be passed or returned by value from a polymorphic function, the translator can safely assume the generic type is complete (\ie has a known layout) at any call-site, and the offset array is passed from the caller;
    510509if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C @offsetof@ macro.
    511 As an example, the body of the second @value@ function is implemented as:
    512 \begin{cfa}
    513 _assign_T( _retval, p + _offsetof_pair[1] ); $\C{// return *p.second}$
    514 \end{cfa}
    515 @_assign_T@ is passed in as an implicit parameter from @otype T@, and takes two @T *@ (@void *@ in the generated code), a destination and a source; @_retval@ is the pointer to a caller-allocated buffer for the return value, the usual \CFA method to handle dynamically-sized return types.
     510As an example, the body of the second @value@ function is implemented like this:
     511\begin{cfa}
     512_assign_T(_retval, p + _offsetof_pair[1]); $\C{// return *p.second}$
     513\end{cfa}
     514@_assign_T@ is passed in as an implicit parameter from @otype T@, and takes two @T*@ (@void*@ in the generated code), a destination and a source; @_retval@ is the pointer to a caller-allocated buffer for the return value, the usual \CFA method to handle dynamically-sized return types.
    516515@_offsetof_pair@ is the offset array passed into @value@; this array is generated at the call site as:
    517516\begin{cfa}
    518 size_t _offsetof_pair[] = { offsetof( _pair_conc0, first ), offsetof( _pair_conc0, second ) }
     517size_t _offsetof_pair[] = { offsetof(_pair_conc0, first), offsetof(_pair_conc0, second) }
    519518\end{cfa}
    520519
     
    540539The most important such pattern is using @forall(dtype T) T *@ as a type-checked replacement for @void *@, \eg creating a lexicographic comparison for pairs of pointers used by @bsearch@ or @qsort@:
    541540\begin{cfa}
    542 forall( dtype T ) int lexcmp( pair( T *, T * ) * a, pair( T *, T * ) * b, int (* cmp)( T *, T * ) ) {
     541forall(dtype T) int lexcmp( pair( T *, T * ) * a, pair( T *, T * ) * b, int (* cmp)( T *, T * ) ) {
    543542        return cmp( a->first, b->first ) ? : cmp( a->second, b->second );
    544543}
    545544\end{cfa}
    546 Since @pair( T *, T * )@ is a concrete type, there are no implicit parameters passed to @lexcmp@, so the generated code is identical to a function written in standard C using @void *@, yet the \CFA version is type-checked to ensure the fields of both pairs and the arguments to the comparison function match in type.
     545Since @pair(T *, T * )@ is a concrete type, there are no implicit parameters passed to @lexcmp@, so the generated code is identical to a function written in standard C using @void *@, yet the \CFA version is type-checked to ensure the fields of both pairs and the arguments to the comparison function match in type.
    547546
    548547Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \newterm{tag-structures}.
    549548Sometimes information is only used for type-checking and can be omitted at runtime, \eg:
    550549\begin{cfa}
    551 forall( dtype Unit ) struct scalar { unsigned long value; };
     550forall(dtype Unit) struct scalar { unsigned long value; };
    552551struct metres {};
    553552struct litres {};
    554553
    555 forall( dtype U) scalar(U) ?+?( scalar(U) a, scalar(U) b ) {
     554forall(dtype U) scalar(U) ?+?( scalar(U) a, scalar(U) b ) {
    556555        return (scalar(U)){ a.value + b.value };
    557556}
     
    808807Due to the implicit flattening and structuring conversions involved in argument passing, @otype@ and @dtype@ parameters are restricted to matching only with non-tuple types, \eg:
    809808\begin{cfa}
    810 forall( otype T, dtype U ) void f( T x, U * y );
     809forall(otype T, dtype U) void f( T x, U * y );
    811810f( [5, "hello"] );
    812811\end{cfa}
     
    815814For example, a plus operator can be written to add two triples together.
    816815\begin{cfa}
    817 forall( otype T | { T ?+?( T, T ); } ) [T, T, T] ?+?( [T, T, T] x, [T, T, T] y ) {
     816forall(otype T | { T ?+?( T, T ); }) [T, T, T] ?+?( [T, T, T] x, [T, T, T] y ) {
    818817        return [x.0 + y.0, x.1 + y.1, x.2 + y.2];
    819818}
     
    826825\begin{cfa}
    827826int f( [int, double], double );
    828 forall( otype T, otype U | { T f( T, U, U ); } ) void g( T, U );
     827forall(otype T, otype U | { T f( T, U, U ); }) void g( T, U );
    829828g( 5, 10.21 );
    830829\end{cfa}
     
    853852\begin{cfa}
    854853int sum$\(_0\)$() { return 0; }
    855 forall( ttype Params | { int sum( Params ); } ) int sum$\(_1\)$( int x, Params rest ) {
     854forall(ttype Params | { int sum( Params ); } ) int sum$\(_1\)$( int x, Params rest ) {
    856855        return x + sum( rest );
    857856}
     
    866865\begin{cfa}
    867866int sum( int x, int y ) { return x + y; }
    868 forall( ttype Params | { int sum( int, Params ); } ) int sum( int x, int y, Params rest ) {
     867forall(ttype Params | { int sum( int, Params ); } ) int sum( int x, int y, Params rest ) {
    869868        return sum( x + y, rest );
    870869}
     
    872871One more step permits the summation of any summable type with all arguments of the same type:
    873872\begin{cfa}
    874 trait summable( otype T ) {
     873trait summable(otype T) {
    875874        T ?+?( T, T );
    876875};
    877 forall( otype R | summable( R ) ) R sum( R x, R y ) {
     876forall(otype R | summable( R ) ) R sum( R x, R y ) {
    878877        return x + y;
    879878}
    880 forall( otype R, ttype Params | summable(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) {
     879forall(otype R, ttype Params | summable(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) {
    881880        return sum( x + y, rest );
    882881}
     
    889888\begin{cfa}
    890889struct S { int x, y; };
    891 forall( otype T, ttype Params | { void print(T); void print(Params); } ) void print(T arg, Params rest) {
     890forall(otype T, ttype Params | { void print(T); void print(Params); }) void print(T arg, Params rest) {
    892891        print(arg);  print(rest);
    893892}
     
    928927is transformed into:
    929928\begin{cfa}
    930 forall( dtype T0, dtype T1 | sized(T0) | sized(T1) ) struct _tuple2 {
     929forall(dtype T0, dtype T1 | sized(T0) | sized(T1)) struct _tuple2 {
    931930        T0 field_0;                                                             $\C{// generated before the first 2-tuple}$
    932931        T1 field_1;
     
    934933_tuple2(int, int) f() {
    935934        _tuple2(double, double) x;
    936         forall( dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2) ) struct _tuple3 {
     935        forall(dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2)) struct _tuple3 {
    937936                T0 field_0;                                                     $\C{// generated before the first 3-tuple}$
    938937                T1 field_1;
     
    942941}
    943942\end{cfa}
    944 {\sloppy
     943\begin{sloppypar}
    945944Tuple expressions are then simply converted directly into compound literals, \eg @[5, 'x', 1.24]@ becomes @(_tuple3(int, char, double)){ 5, 'x', 1.24 }@.
    946 \par}%
     945\end{sloppypar}
    947946
    948947\begin{comment}
     
    10081007
    10091008
    1010 \subsection{\texorpdfstring{\protect\lstinline{if} Statement}{if Statement}}
     1009\subsection{\texorpdfstring{\LstKeywordStyle{if} Statement}{if Statement}}
    10111010
    10121011The @if@ expression allows declarations, similar to @for@ declaration expression:
     
    10201019
    10211020
    1022 \subsection{\texorpdfstring{\protect\lstinline{switch} Statement}{switch Statement}}
     1021\subsection{\texorpdfstring{\LstKeywordStyle{switch} Statement}{switch Statement}}
    10231022
    10241023There are a number of deficiencies with the C @switch@ statements: enumerating @case@ lists, placement of @case@ clauses, scope of the switch body, and fall through between case clauses.
     
    10911090C @switch@ provides multiple entry points into the statement body, but once an entry point is selected, control continues across \emph{all} @case@ clauses until the end of the @switch@ body, called \newterm{fall through};
    10921091@case@ clauses are made disjoint by the @break@ statement.
    1093 While fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in errors from missing @break@ statements.
    1094 For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through (see Figure~\ref{f:ChooseSwitchStatements}), similar to Go.
     1092While the ability to fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in many errors from missing @break@ statements.
     1093For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through (see Figure~\ref{f:ChooseSwitchStatements}).
     1094
     1095Collectively, these enhancements reduce programmer burden and increase readability and safety.
    10951096
    10961097\begin{figure}
     
    11361137\end{figure}
    11371138
    1138 Finally, @fallthrough@ may appear in contexts other than terminating a @case@ clause, and have an explicit transfer label allowing separate cases but common final-code for a set of cases:
    1139 \begin{cquote}
    1140 \lstDeleteShortInline@%
    1141 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}
    1142 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{non-terminator}}  & \multicolumn{1}{c}{\textbf{target label}}     \\
    1143 \begin{cfa}
    1144 choose ( ... ) {
    1145   case 3:
    1146         if ( ... ) {
    1147                 ... `fallthrough;`  // goto case 4
    1148         } else {
    1149                 ...
    1150         }
    1151         // implicit break
    1152   case 4:
    1153 \end{cfa}
    1154 &
    1155 \begin{cfa}
    1156 choose ( ... ) {
    1157   case 3:
    1158         ... `fallthrough common;`
    1159   case 4:
    1160         ... `fallthrough common;`
    1161   common:
    1162         ...      // common code for cases 3 and 4
    1163         // implicit break
    1164   case 4:
    1165 \end{cfa}
    1166 \end{tabular}
    1167 \lstMakeShortInline@%
    1168 \end{cquote}
    1169 The target label may be case @default@.
    1170 
    1171 Collectively, these control-structure enhancements reduce programmer burden and increase readability and safety.
    1172 
    1173 
    1174 \subsection{\texorpdfstring{Labelled \protect\lstinline{continue} / \protect\lstinline{break}}{Labelled continue / break}}
     1139\begin{comment}
     1140Forgotten @break@ statements at the end of @switch@ cases are a persistent sort of programmer error in C, and the @break@ statements themselves introduce visual clutter and an un-C-like keyword-based block delimiter.
     1141\CFA addresses this error by introducing a @choose@ statement, which works identically to a @switch@ except that its default end-of-case behaviour is to break rather than to fall through for all non-empty cases.
     1142Since empty cases like @case 7:@ in @case 7: case 11:@ still have fall-through semantics and explicit @break@ is still allowed at the end of a @choose@ case, many idiomatic uses of @switch@ in standard C can be converted to @choose@ statements by simply changing the keyword.
     1143Where fall-through is desired for a non-empty case, it can be specified with the new @fallthrough@ statement, making @choose@ equivalently powerful to @switch@, but more concise in the common case where most non-empty cases end with a @break@ statement, as in the example below:
     1144
     1145\begin{cfa}
     1146choose( i ) {
     1147        case 2:
     1148                printf("even ");
     1149                fallthrough;
     1150        case 3: case 5: case 7:
     1151                printf("small prime\n");
     1152        case 4,6,8,9:
     1153                printf("small composite\n");
     1154        case 13~19:
     1155                printf("teen\n");
     1156        default:
     1157                printf("something else\n");
     1158}
     1159\end{cfa}
     1160\end{comment}
     1161
     1162
     1163\subsection{\texorpdfstring{Labelled \LstKeywordStyle{continue} / \LstKeywordStyle{break}}{Labelled continue / break}}
    11751164
    11761165While C provides @continue@ and @break@ statements for altering control flow, both are restricted to one level of nesting for a particular control structure.
     
    12811270\subsection{Exception Handling}
    12821271
    1283 The following framework for \CFA exception handling is in place, excluding some runtime type-information and virtual functions.
     1272The following framework for \CFA exception handling is in place, excluding some run-time type-information and dynamic casts.
    12841273\CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling})~\cite{Buhr92b,Buhr00a}.
    12851274Both 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.
     
    13511340   catch ( IOError err ) { ... }                        $\C{// handler error from other files}$
    13521341\end{cfa}
    1353 where the throw inserts the failing file-handle into the I/O exception.
     1342where the throw inserts the failing file-handle in the I/O exception.
    13541343Conditional catch cannot be trivially mimicked by other mechanisms because once an exception is caught, handler clauses in that @try@ statement are no longer eligible..
    13551344
     
    13591348resume( $\emph{alternate-stack}$ )
    13601349\end{cfa}
    1361 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}.
    1362 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.
    1363 
    1364 To facilitate nonlocal raise, \CFA provides dynamic enabling and disabling of nonlocal exception-propagation.
     1350These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task~\cite{Delisle18}.\footnote{\CFA coroutine and concurrency features are discussed in a separately submitted paper.}
     1351Nonlocal raise is restricted to resumption to provide the exception handler the greatest flexibility because processing the exception does not unwind its stack, allowing it to continue after the handle returns.
     1352
     1353To facilitate nonlocal exception, \CFA provides dynamic enabling and disabling of nonlocal exception-propagation.
    13651354The constructs for controlling propagation of nonlocal exceptions are the @enable@ and the @disable@ blocks:
    13661355\begin{cquote}
     
    13691358\begin{cfa}
    13701359enable $\emph{exception-type-list}$ {
    1371         // allow non-local raise
     1360        // allow non-local resumption
    13721361}
    13731362\end{cfa}
     
    13751364\begin{cfa}
    13761365disable $\emph{exception-type-list}$ {
    1377         // disallow non-local raise
     1366        // disallow non-local resumption
    13781367}
    13791368\end{cfa}
     
    13861375Coroutines and tasks start with non-local exceptions disabled, allowing handlers to be put in place, before non-local exceptions are explicitly enabled.
    13871376\begin{cfa}
    1388 void main( mytask & t ) {                                       $\C{// thread starts here}$
     1377void main( mytask & c ) {                                       $\C{// thread starts here}$
    13891378        // non-local exceptions disabled
    13901379        try {                                                                   $\C{// establish handles for non-local exceptions}$
     
    14121401
    14131402
    1414 \subsection{\texorpdfstring{\protect\lstinline{with} Clause / Statement}{with Clause / Statement}}
     1403\subsection{\texorpdfstring{\LstKeywordStyle{with} Clause / Statement}{with Clause / Statement}}
    14151404\label{s:WithClauseStatement}
    14161405
     
    27352724user defined: D, Objective-C
    27362725
    2737 
    27382726\section{Conclusion and Future Work}
    27392727
     
    27482736Finally, we demonstrate that \CFA performance for some idiomatic cases is better than C and close to \CC, showing the design is practically applicable.
    27492737
    2750 There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, runtime type-information, virtual functions, user-defined conversions, concurrent primitives, and modules.
     2738There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, user-defined conversions, concurrent primitives, and modules.
    27512739(While all examples in the paper compile and run, a public beta-release of \CFA will take another 8--12 months to finalize these additional extensions.)
    27522740In addition, there are interesting future directions for the polymorphism design.
     
    27832771\CFA
    27842772\begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2785 forall( otype T ) struct stack_node;
    2786 forall( otype T ) struct stack {
     2773forall(otype T) struct stack_node;
     2774forall(otype T) struct stack {
    27872775        stack_node(T) * head;
    27882776};
    2789 forall( otype T ) struct stack_node {
     2777forall(otype T) struct stack_node {
    27902778        T value;
    27912779        stack_node(T) * next;
    27922780};
    2793 forall( otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
    2794 forall( otype T) void ?{}( stack(T) & s, stack(T) t ) {
     2781forall(otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
     2782forall(otype T) void ?{}( stack(T) & s, stack(T) t ) {
    27952783        stack_node(T) ** crnt = &s.head;
    27962784        for ( stack_node(T) * next = t.head; next; next = next->next ) {
     
    28032791        *crnt = 0;
    28042792}
    2805 forall( otype T ) stack(T) ?=?( stack(T) & s, stack(T) t ) {
     2793forall(otype T) stack(T) ?=?( stack(T) & s, stack(T) t ) {
    28062794        if ( s.head == t.head ) return s;
    28072795        clear( s );
     
    28092797        return s;
    28102798}
    2811 forall( otype T ) void ^?{}( stack(T) & s) { clear( s ); }
    2812 forall( otype T ) _Bool empty( const stack(T) & s ) { return s.head == 0; }
    2813 forall( otype T ) void push( stack(T) & s, T value ) {
     2799forall(otype T) void ^?{}( stack(T) & s) { clear( s ); }
     2800forall(otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; }
     2801forall(otype T) void push( stack(T) & s, T value ) {
    28142802        stack_node(T) * new_node = ((stack_node(T)*)malloc());
    28152803        (*new_node){ value, s.head }; /***/
    28162804        s.head = new_node;
    28172805}
    2818 forall( otype T ) T pop( stack(T) & s ) {
     2806forall(otype T) T pop( stack(T) & s ) {
    28192807        stack_node(T) * n = s.head;
    28202808        s.head = n->next;
     
    28232811        return v;
    28242812}
    2825 forall( otype T ) void clear( stack(T) & s ) {
     2813forall(otype T) void clear( stack(T) & s ) {
    28262814        for ( stack_node(T) * next = s.head; next; ) {
    28272815                stack_node(T) * crnt = next;
Note: See TracChangeset for help on using the changeset viewer.