Changeset 59c05958 for doc/theses/colby_parsons_MMAth/text/CFA_intro.tex
- Timestamp:
- Apr 4, 2023, 10:09:19 AM (17 months ago)
- Branches:
- ADT, ast-experimental, master
- Children:
- 55fabac
- Parents:
- 9363b1b
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/colby_parsons_MMAth/text/CFA_intro.tex
r9363b1b r59c05958 7 7 \section{Overview} 8 8 The following serves as an introduction to \CFA. 9 \CFA is a layer over C, is transpiled to Cand is largely considered to be an extension of C.10 Beyond C, it adds productivity features, libraries, a type system, and many other languageconstructions.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 limitedinheritance.13 \CFA is rich with interesting features, but a subset that is pertinent to this work will bediscussed.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. 10 Beyond C, it adds productivity features, extended libraries, an advanced type system, and many control-flow/concurrency constructions. 11 However, \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. 13 While \CFA is rich with interesting features, only the subset pertinent to this work is discussed. 14 14 15 15 \section{References} 16 References in \CFA are similar to references in \CC , however in\CFA references are rebindable, and support multi-level referencing.16 References in \CFA are similar to references in \CC; however \CFA references are rebindable, and support multi-level referencing. 17 17 References 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@. 18 Another difference is the use of @0p@ instead of C's @NULL@ or \CC's @nullptr@. 19 Examples of references are shown in \VRef[Listing]{l:cfa_ref}. 20 20 21 21 \begin{cfa}[caption={Example of \CFA references},label={l:cfa_ref}] 22 22 int i = 2; 23 int & ref_i = i; $\C[1.5in]{// declare ref to i}$24 int * ptr_i = &i; $\C{// ptr to i}$23 int & ref_i = i; $\C{// declare ref to i}$ 24 int * ptr_i = &i; $\C{// ptr to i}$ 25 25 26 26 // address of ref_i is the same as address of i 27 27 assert( &ref_i == ptr_i ); 28 28 29 int && ref_ref_i = ref_i; 30 ref_i = 3; 29 int && ref_ref_i = ref_i; $\C{// can have a ref to a ref}$ 30 ref_i = 3; $\C{// set i to 3}$ 31 31 int new_i = 4; 32 32 33 33 // 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}. 40 40 Variables 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 functionoverloading},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 41 A routine or variable is disambiguated at each usage site via its type and surrounding expression context. 42 A cast is used to disambiguate any conflicting usage. 43 Examples of overloading are shown in \VRef[Listing]{l:cfa_overload}. 44 45 \begin{cfa}[caption={Example of \CFA overloading},label={l:cfa_overload}] 46 int foo() { sout | "A"; return 0;} 47 int foo( int bar ) { sout | "B"; return 1; } 48 int foo( double bar ) { sout | "C"; return 2; } 49 double foo( double bar ) { sout | "D"; return 3; } 50 void foo( double bar ) { sout | bar; } 51 52 int 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}$ 58 58 } 59 59 \end{cfa} … … 61 61 62 62 \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: 63 The \CFA @with@ statement is for exposing fields of an aggregate type within a scope, allowing field names without qualification. 64 This feature is also implemented in Pascal~\cite{Pascal}. 65 It can exist as a stand-alone statement or wrap a routine body to expose aggregate fields. 66 Examples 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}] 69 struct pair { double x, y; }; 70 struct triple { int a, b, c; }; 79 71 pair 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 } 77 void 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}$ 101 80 } 102 81 \end{cfa} … … 105 84 \section{Operators} 106 85 Operators 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}] 86 Operators in \CFA are named using an operator symbol and '@?@' to represent operands. 87 Examples of \CFA operators are shown in \VRef[Listing]{l:cfa_operate}. 88 89 \begin{cfa}[caption={Example of \CFA operators},label={l:cfa_operate}] 112 90 struct 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 }; 93 coord ++@?@( coord & c ) with( c ) { $\C{// post increment}$ 94 x++; y++; z++; 95 return c; 96 } 97 coord @?@<=@?@( 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); 126 99 } 127 100 \end{cfa} … … 129 102 130 103 \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}] 104 Constructors and destructors in \CFA are special operator routines used for creation and destruction of objects. 105 The default constructor and destructor for a type are called implicitly upon creation and deletion, respectively. 106 Examples 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}] 137 109 struct 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 }; 112 void ?{}( discrete_point & this ) with(this) { $\C{// default constructor}$ 113 [x, y] = 0; 114 } 115 void ?{}( discrete_point & this, int x, int y ) { $\C{// explicit constructor}$ 116 this.[x, y] = [x, y]; 117 } 118 void ^?{}( discrete_point & this ) with(this) { $\C{// destructor}$ 119 ?{}( this ); $\C{// reset by calling default constructor}$ 120 } 121 int 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 159 125 \end{cfa} 160 126 161 127 162 128 \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.129 C 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. 165 131 166 132 \subsection{Parametric Polymorphism} … … 168 134 A @forall@ takes in a set of types and a list of constraints. 169 135 The 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}] 136 A list of @forall@ constraints can be refactored into a named @trait@ and reused in @forall@s. 137 Examples 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}] 175 140 // sized() is a trait that means the type has a size 176 forall( V & | sized(V) ) // type params for trait141 forall( V & | sized(V) ) $\C{// type params for trait}$ 177 142 trait 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 150 forall( 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 } 193 157 } 194 158 struct Vec1 { int x; }; … … 196 160 void ?{}( Vec1 & this, int x ) { this.x = x; } 197 161 void ^?{}( 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; }162 Vec1 ?+?( Vec1 v1, Vec1 v2 ) { v1.x += v2.x; return v1; } 163 Vec1 ?*?( int c, Vec1 v1 ) { v1.x = v1.x * c; return v1; } 200 164 201 165 struct Vec2 { int x; int y; }; … … 203 167 void ?{}( Vec2 & this, int x ) { this.x = x; this.y = x; } 204 168 void ^?{}( 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 169 Vec2 ?+?( Vec2 v1, Vec2 v2 ) { v1.x += v2.x; v1.y += v2.y; return v1; } 170 Vec2 ?*?( int c, Vec2 v1 ) { v1.x = v1.x * c; v1.y = v1.y * c; return v1; } 171 172 int 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 } 217 179 \end{cfa} 218 180 219 181 \subsection{Inheritance} 220 Inheritance in \CFA copies its style from Plan-9 C nominalinheritance.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 inlinedtype.222 An example of \CFA inheritance is shown in Listing~\ref{l:cfa_inherit}. 223 224 \begin{cfa}[ tabsize=3,caption={Example of \CFAinheritance},label={l:cfa_inherit}]182 Inheritance in \CFA is taken from Plan-9 C's containment inheritance. 183 In \CFA, @struct@s can @inline@ another struct type to gain its fields and masquerade as that type. 184 Examples 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}] 225 187 struct one_d { double x; }; 226 188 struct two_d { 227 inlineone_d;228 189 @inline@ one_d; 190 double y; 229 191 }; 230 192 struct three_d { 231 inlinetwo_d;232 193 @inline@ two_d; 194 double z; 233 195 }; 234 196 double get_x( one_d & d ){ return d.x; } … … 236 198 struct dog {}; 237 199 struct dog_food { 238 200 int count; 239 201 }; 240 202 struct 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 }; 206 void pet_dog( dog & d ) { sout | "woof"; } 207 void print_food( dog_food & f ) { sout | f.count; } 208 209 int 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.