Changeset 59c05958


Ignore:
Timestamp:
Apr 4, 2023, 10:09:19 AM (13 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, ast-experimental, master
Children:
55fabac
Parents:
9363b1b
Message:

proofread CFA-introduction chapter

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/colby_parsons_MMAth/text/CFA_intro.tex

    r9363b1b r59c05958  
    77\section{Overview}
    88The following serves as an introduction to \CFA.
    9 \CFA is a layer over C, is transpiled to C and is largely considered to be an extension of C.
    10 Beyond C, it adds productivity features, libraries, a type system, and many other language constructions.
    11 However, \CFA stays true to C as a language, with most code revolving around @struct@'s and routines, and respects the same rules as C.
    12 \CFA is not object oriented as it has no notion of @this@ and no classes or methods, but supports some object oriented adjacent ideas including costructors, destructors, and limited inheritance.
    13 \CFA is rich with interesting features, but a subset that is pertinent to this work will be discussed.
     9\CFA is a layer over C, is transpiled\footnote{Source to source translator.} to C, and is largely considered to be an extension of C.
     10Beyond C, it adds productivity features, extended libraries, an advanced type system, and many control-flow/concurrency constructions.
     11However, \CFA stays true to the C programming style, with most code revolving around @struct@'s and routines, and respects the same rules as C.
     12\CFA is not object oriented as it has no notion of @this@ (receiver) and no structures with methods, but supports some object oriented ideas including constructors, destructors, and limited containment inheritance.
     13While \CFA is rich with interesting features, only the subset pertinent to this work is discussed.
    1414
    1515\section{References}
    16 References in \CFA are similar to references in \CC, however in \CFA references are rebindable, and support multi-level referencing.
     16References in \CFA are similar to references in \CC; however \CFA references are rebindable, and support multi-level referencing.
    1717References in \CFA are a layer of syntactic sugar over pointers to reduce the number of ref/deref operations needed with pointer usage.
    18 Some examples of references in \CFA are shown in Listing~\ref{l:cfa_ref}.
    19 Another related item to note is that the \CFA equivalent of \CC's @nullptr@ is @0p@.
     18Another difference is the use of @0p@ instead of C's @NULL@ or \CC's @nullptr@.
     19Examples of references are shown in \VRef[Listing]{l:cfa_ref}.
    2020
    2121\begin{cfa}[caption={Example of \CFA references},label={l:cfa_ref}]
    2222int i = 2;
    23 int & ref_i = i;        $\C[1.5in]{// declare ref to i}$
    24 int * ptr_i = &i;       $\C{// ptr to i}$
     23int & ref_i = i;                        $\C{// declare ref to i}$
     24int * ptr_i = &i;                       $\C{// ptr to i}$
    2525
    2626// address of ref_i is the same as address of i
    2727assert( &ref_i == ptr_i );
    2828
    29 int && ref_ref_i = ref_i;   $\C{// can have a ref to a ref}$
    30 ref_i = 3;                  $\C{// set i to 3}$
     29int && ref_ref_i = ref_i;       $\C{// can have a ref to a ref}$
     30ref_i = 3;                                      $\C{// set i to 3}$
    3131int new_i = 4;
    3232
    3333// syntax to rebind ref_i (must cancel implicit deref)
    34 &ref_i = &new_i;        $\C{// (\&*)ref\_i = \&new\_i; (sets underlying ptr)}\CRT$
    35 \end{cfa}
    36 
    37 
    38 \section{Overloading}
    39 In \CFA routines can be overloaded on parameter type, number of parameters, and return type.
     34&ref_i = &new_i;                        $\C{// (\&*)ref\_i = \&new\_i; (sets underlying ptr)}$
     35\end{cfa}
     36
     37
     38\section{Overloading}\label{s:Overloading}
     39\CFA routines can be overloaded on parameter type, number of parameters, and \emph{return type}.
    4040Variables can also be overloaded on type, meaning that two variables can have the same name so long as they have different types.
    41 The variables will be disambiguated via type, sometimes requiring a cast.
    42 The code snippet in Listing~\ref{l:cfa_overload} contains examples of overloading.
    43 
    44 
    45 \begin{cfa}[caption={Example of \CFA function overloading},label={l:cfa_overload}]
    46 int foo() { printf("A\n");  return 0;}
    47 int foo( int bar ) { printf("B\n"); return 1; }
    48 int foo( double bar ) { printf("C\n"); return 2; }
    49 double foo( double bar ) { printf("D\n"); return 3;}
    50 void foo( double bar ) { printf("%.0f\n", bar); }
    51 
    52 int main() {
    53     foo();                  // prints A
    54     foo( 0 );               // prints B
    55     int a = foo( 0.0 );     // prints C
    56     double a = foo( 0.0 );  // prints D
    57     foo( a );               // prints 3
     41A routine or variable is disambiguated at each usage site via its type and surrounding expression context.
     42A cast is used to disambiguate any conflicting usage.
     43Examples of overloading are shown in \VRef[Listing]{l:cfa_overload}.
     44
     45\begin{cfa}[caption={Example of \CFA overloading},label={l:cfa_overload}]
     46int foo() { sout | "A";  return 0;}
     47int foo( int bar ) { sout | "B"; return 1; }
     48int foo( double bar ) { sout | "C"; return 2; }
     49double foo( double bar ) { sout | "D"; return 3; }
     50void foo( double bar ) { sout | bar; }
     51
     52int main() {
     53        foo();                                          $\C{// prints A}$
     54        foo( 0 );                                       $\C{// prints B}$
     55        int foo = foo( 0.0 );           $\C{// prints C}$
     56        double foo = foo( 0.0 );        $\C{// prints D}$
     57        foo( foo );                                     $\C{// prints 3., where left-hand side of expression is void}$
    5858}
    5959\end{cfa}
     
    6161
    6262\section{With Statement}
    63 The with statement is a tool for exposing members of aggregate types within a scope in \CFA.
    64 It allows users to use fields of aggregate types without using their fully qualified name.
    65 This feature is also implemented in Pascal.
    66 It can exist as a stand-alone statement or it can be used on routines to expose fields in the body of the routine.
    67 An example is shown in Listing~\ref{l:cfa_with}.
    68 
    69 
    70 \begin{cfa}[tabsize=3,caption={Usage of \CFA with statement},label={l:cfa_with}]
    71 struct obj {
    72     int a, b, c;
    73 };
    74 struct pair {
    75     double x, y;
    76 };
    77 
    78 // Stand-alone with stmt:
     63The \CFA @with@ statement is for exposing fields of an aggregate type within a scope, allowing field names without qualification.
     64This feature is also implemented in Pascal~\cite{Pascal}.
     65It can exist as a stand-alone statement or wrap a routine body to expose aggregate fields.
     66Examples of the @with@ statement are shown in \VRef[Listing]{l:cfa_with}.
     67
     68\begin{cfa}[caption={Example of \CFA \lstinline{with} statement},label={l:cfa_with}]
     69struct pair {  double x, y;  };
     70struct triple {  int a, b, c;  };
    7971pair p;
    80 with( p ) {
    81     x = 6.28;
    82     y = 1.73;
    83 }
    84 
    85 // Can be used on routines:
    86 void foo( obj o, pair p ) with( o, p ) {
    87     a = 1;
    88     b = 2;
    89     c = 3;
    90     x = 3.14;
    91     y = 2.71;
    92 }
    93 
    94 // routine foo is equivalent to routine bar:
    95 void bar( obj o, pair p ) {
    96     o.a = 1;
    97     o.b = 2;
    98     o.c = 3;
    99     p.x = 3.14;
    100     p.y = 2.71;
     72
     73@with( p )@ {                                   $\C{// stand-alone with}$
     74        p.x = 6.28;  p.y = 1.73;        $\C{// long form}$
     75           x = 6.28;     y = 1.73;      $\C{// short form}$
     76}
     77void foo( triple t, pair p ) @with( t, p )@ {  $\C{// routine with}$
     78        t.a = 1;  t.b = 2;  t.c = 3;  p.x = 3.14;  p.y = 2.71;  $\C{// long form}$
     79          a = 1;    b = 2;    c = 3;     x = 3.14;     y = 2.71;  $\C{// short form}$
    10180}
    10281\end{cfa}
     
    10584\section{Operators}
    10685Operators can be overloaded in \CFA with operator routines.
    107 Operators in \CFA are named using the operator symbol and '?' to respresent operands.
    108 An example is shown in Listing~\ref{l:cfa_operate}.
    109 
    110 
    111 \begin{cfa}[tabsize=3,caption={Example of \CFA operators},label={l:cfa_operate}]
     86Operators in \CFA are named using an operator symbol and '@?@' to represent operands.
     87Examples of \CFA operators are shown in \VRef[Listing]{l:cfa_operate}.
     88
     89\begin{cfa}[caption={Example of \CFA operators},label={l:cfa_operate}]
    11290struct coord {
    113     double x;
    114     double y;
    115     double z;
    116 };
    117 coord ++?( coord & c ) with(c) {
    118     x++;
    119     y++;
    120     z++;
    121     return c;
    122 }
    123 coord ?<=?( coord op1, coord op2 ) with( op1 ) {
    124     return (x*x + y*y + z*z) <=
    125         (op2.x*op2.x + op2.y*op2.y + op2.z*op2.z);
     91        double x, y, z;
     92};
     93coord ++@?@( coord & c ) with( c ) { $\C{// post increment}$
     94        x++;  y++;  z++;
     95        return c;
     96}
     97coord @?@<=@?@( coord op1, coord op2 ) with( op1 ) { $\C{// ambiguous with both parameters}$
     98        return (x * x + y * y + z * z) <= (op2.x * op2.x + op2.y * op2.y + op2.z * op2.z);
    12699}
    127100\end{cfa}
     
    129102
    130103\section{Constructors and Destructors}
    131 Constructors and destructors in \CFA are two special operator routines that are used for creation and destruction of objects.
    132 The default constructor and destructor for a type are called implicitly upon creation and deletion respectively if they are defined.
    133 An example is shown in Listing~\ref{l:cfa_ctor}.
    134 
    135 
    136 \begin{cfa}[tabsize=3,caption={Example of \CFA constructors and destructors},label={l:cfa_ctor}]
     104Constructors and destructors in \CFA are special operator routines used for creation and destruction of objects.
     105The default constructor and destructor for a type are called implicitly upon creation and deletion, respectively.
     106Examples of \CFA constructors and destructors are shown in \VRef[Listing]{l:cfa_ctor}.
     107
     108\begin{cfa}[caption={Example of \CFA constructors and destructors},label={l:cfa_ctor}]
    137109struct discrete_point {
    138     int x;
    139     int y;
    140 };
    141 void ?{}( discrete_point & this ) with(this) { // ctor
    142     x = 0;
    143     y = 0;
    144 }
    145 void ?{}( discrete_point & this, int x, int y ) { // ctor
    146     this.x = x;
    147     this.y = y;
    148 }
    149 void ^?{}( discrete_point & this ) with(this) { // dtor
    150     x = 0;
    151     y = 0;
    152 }
    153 
    154 int main() {
    155     discrete_point d; // implicit call to ?{}
    156     discrete_point p{}; // same call as line above
    157     discrete_point dp{ 2, -4 }; // specialized ctor
    158 } // ^d{}, ^p{}, ^dp{} all called as they go out of scope
     110        int x, y;
     111};
     112void ?{}( discrete_point & this ) with(this) { $\C{// default constructor}$
     113        [x, y] = 0;
     114}
     115void ?{}( discrete_point & this, int x, int y ) { $\C{// explicit constructor}$
     116        this.[x, y] = [x, y];
     117}
     118void ^?{}( discrete_point & this ) with(this) { $\C{// destructor}$
     119        ?{}( this );  $\C{// reset by calling default constructor}$
     120}
     121int main() {
     122        discrete_point x, y{};  $\C{// implicit call to default ctor, ?\{\}}$
     123        discrete_point s = { 2, -4 }, t{ 4, 2 };  $\C{// explicit call to specialized ctor}$
     124} // ^t{}, ^s{}, ^y{}, ^x{} implicit calls in reverse allocation order
    159125\end{cfa}
    160126
    161127
    162128\section{Polymorphism}\label{s:poly}
    163 C does not natively support polymorphism, and requires users to implement polymorphism themselves if they want to use it.
    164 \CFA extends C with two styles of polymorphism that it supports, parametric polymorphism and nominal inheritance.
     129C supports limited polymorphism, often requiring users to implement polymorphism using a @void *@ (type erasure) approach.
     130\CFA extends C with generalized overloading polymorphism (see \VRef{s:Overloading}), as well as, parametric polymorphism and nominal inheritance.
    165131
    166132\subsection{Parametric Polymorphism}
     
    168134A @forall@ takes in a set of types and a list of constraints.
    169135The declarations that follow the @forall@ are parameterized over the types listed that satisfy the constraints.
    170 Sometimes the list of constraints can be long, which is where a @trait@ can be used.
    171 A @trait@ is a collection of constraints that is given a name and can be reused in foralls.
    172 An example of the usage of parametric polymorphism in \CFA is shown in Listing~\ref{l:cfa_poly}.
    173 
    174 \begin{cfa}[tabsize=3,caption={Example of \CFA polymorphism},label={l:cfa_poly}]
     136A list of @forall@ constraints can be refactored into a named @trait@ and reused in @forall@s.
     137Examples of \CFA parametric polymorphism are shown in \VRef[Listing]{l:cfa_poly}.
     138
     139\begin{cfa}[caption={Example of \CFA parametric polymorphism},label={l:cfa_poly}]
    175140// sized() is a trait that means the type has a size
    176 forall( V & | sized(V) )        // type params for trait
     141forall( V & | sized(V) )                $\C{// type params for trait}$
    177142trait vector_space {
    178     V add( V, V );              // vector addition
    179     V scalar_mult( int, V );    // scalar multiplication
    180 
    181     // dtor and copy ctor needed in constraints to pass by copy
    182     void ?{}( V &, V & );       // copy ctor for return
    183     void ^?{}( V & );           // dtor
    184 };
    185 
    186 forall( V & | vector_space( V )) {
    187     V get_inverse( V v1 ) {
    188         return scalar_mult( -1, v1 );  // can use ?*? routine defined in trait
    189     }
    190     V add_and_invert( V v1, V v2 ) {
    191         return get_inverse( add( v1, v2 ) );  // can use ?*? routine defined in trait
    192     }
     143        // dtor and copy ctor needed in constraints to pass by copy
     144        void ?{}( V &, V & );           $\C{// copy ctor for return}$
     145        void ^?{}( V & );                       $\C{// dtor}$
     146        V ?+?( V, V );                          $\C{// vector addition}$
     147        V ?*?( int, V );                        $\C{// scalar multiplication}$
     148};
     149
     150forall( V & | vector_space( V ) ) {
     151        V get_inverse( V v1 ) {
     152                return -1 * v1;                 $\C{// can use ?*? routine defined in trait}$
     153        }
     154        V add_and_invert( V v1, V v2 ) {
     155                return get_inverse( v1 + v2 );  $\C{// can use ?+? routine defined in trait}$
     156        }
    193157}
    194158struct Vec1 { int x; };
     
    196160void ?{}( Vec1 & this, int x ) { this.x = x; }
    197161void ^?{}( Vec1 & this ) {}
    198 Vec1 add( Vec1 v1, Vec1 v2 ) { v1.x += v2.x; return v1; }
    199 Vec1 scalar_mult( int c, Vec1 v1 ) { v1.x = v1.x * c; return v1; }
     162Vec1 ?+?( Vec1 v1, Vec1 v2 ) { v1.x += v2.x; return v1; }
     163Vec1 ?*?( int c, Vec1 v1 ) { v1.x = v1.x * c; return v1; }
    200164
    201165struct Vec2 { int x; int y; };
     
    203167void ?{}( Vec2 & this, int x ) { this.x = x; this.y = x; }
    204168void ^?{}( Vec2 & this ) {}
    205 Vec2 add( Vec2 v1, Vec2 v2 ) { v1.x += v2.x; v1.y += v2.y; return v1; }
    206 Vec2 scalar_mult( int c, Vec2 v1 ) { v1.x = v1.x * c; v1.y = v1.y * c; return v1; }
    207 
    208 int main() {
    209     Vec1 v1{ 1 }; // create Vec1 and call ctor
    210     Vec2 v2{ 2 }; // create Vec2 and call ctor
    211 
    212     // can use forall defined routines since types satisfy trait
    213     add_and_invert( get_inverse( v1 ), v1 );
    214     add_and_invert( get_inverse( v2 ), v2 );
    215 }
    216 
     169Vec2 ?+?( Vec2 v1, Vec2 v2 ) { v1.x += v2.x; v1.y += v2.y; return v1; }
     170Vec2 ?*?( int c, Vec2 v1 ) { v1.x = v1.x * c; v1.y = v1.y * c; return v1; }
     171
     172int main() {
     173        Vec1 v1{ 1 };                           $\C{// create Vec1 and call ctor}$
     174        Vec2 v2{ 2 };                           $\C{// create Vec2 and call ctor}$
     175        // can use forall defined routines since types satisfy trait
     176        add_and_invert( get_inverse( v1 ), v1 );
     177        add_and_invert( get_inverse( v2 ), v2 );
     178}
    217179\end{cfa}
    218180
    219181\subsection{Inheritance}
    220 Inheritance in \CFA copies its style from Plan-9 C nominal inheritance.
    221 In \CFA structs can @inline@ another struct type to gain its fields and to be able to be passed to routines that require a parameter of the inlined type.
    222 An example of \CFA inheritance is shown in Listing~\ref{l:cfa_inherit}.
    223 
    224 \begin{cfa}[tabsize=3,caption={Example of \CFA inheritance},label={l:cfa_inherit}]
     182Inheritance in \CFA is taken from Plan-9 C's containment inheritance.
     183In \CFA, @struct@s can @inline@ another struct type to gain its fields and masquerade as that type.
     184Examples of \CFA containment inheritance are shown in \VRef[Listing]{l:cfa_inherit}.
     185
     186\begin{cfa}[caption={Example of \CFA containment inheritance},label={l:cfa_inherit}]
    225187struct one_d { double x; };
    226188struct two_d {
    227     inline one_d;
    228     double y;
     189        @inline@ one_d;
     190        double y;
    229191};
    230192struct three_d {
    231     inline two_d;
    232     double z;
     193        @inline@ two_d;
     194        double z;
    233195};
    234196double get_x( one_d & d ){ return d.x; }
     
    236198struct dog {};
    237199struct dog_food {
    238     int count;
     200        int count;
    239201};
    240202struct pet {
    241     inline dog;
    242     inline dog_food;
    243 };
    244 void pet_dog( dog & d ){printf("woof\n");}
    245 void print_food( dog_food & f ){printf("%d\n", f.count);}
    246 
    247 int main() {
    248     one_d x;
    249     two_d y;
    250     three_d z;
    251     x.x = 1;
    252     y.x = 2;
    253     z.x = 3;
    254     get_x( x ); // returns 1;
    255     get_x( y ); // returns 2;
    256     get_x( z ); // returns 3;
    257     pet p;
    258     p.count = 5;
    259     pet_dog( p );    // prints woof
    260     print_food( p ); // prints 5
    261 }
    262 \end{cfa}
    263 
    264 
     203        @inline@ dog;
     204        @inline@ dog_food;
     205};
     206void pet_dog( dog & d ) { sout | "woof"; }
     207void print_food( dog_food & f ) { sout | f.count; }
     208
     209int main() {
     210        one_d x;
     211        two_d y;
     212        three_d z;
     213        x.x = 1;
     214        y.x = 2;
     215        z.x = 3;
     216        get_x( x );                                     $\C{// returns 1;}$
     217        get_x( y );                                     $\C{// returns 2;}$
     218        get_x( z );                                     $\C{// returns 3;}$
     219        pet p;
     220        p.count = 5;
     221        pet_dog( p );                           $\C{// prints woof}$
     222        print_food( p );                        $\C{// prints 5}$
     223}
     224\end{cfa}
     225
     226% Local Variables: %
     227% tab-width: 4 %
     228% fill-column: 100 %
     229% End: %
     230
     231
Note: See TracChangeset for help on using the changeset viewer.