1 | % ====================================================================== |
---|
2 | % ====================================================================== |
---|
3 | \chapter{Introduction to \CFA}\label{s:cfa} |
---|
4 | % ====================================================================== |
---|
5 | % ====================================================================== |
---|
6 | |
---|
7 | \section{Overview} |
---|
8 | The 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. |
---|
14 | |
---|
15 | \section{References} |
---|
16 | References in \CFA are similar to references in \CC, however in \CFA references are rebindable, and support multi-level referencing. |
---|
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@. |
---|
20 | |
---|
21 | \begin{cfa}[caption={Example of \CFA references},label={l:cfa_ref}] |
---|
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}$ |
---|
25 | |
---|
26 | // address of ref_i is the same as address of i |
---|
27 | assert( &ref_i == ptr_i ); |
---|
28 | |
---|
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 | int new_i = 4; |
---|
32 | |
---|
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. |
---|
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 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 |
---|
58 | } |
---|
59 | \end{cfa} |
---|
60 | |
---|
61 | |
---|
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: |
---|
79 | 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; |
---|
101 | } |
---|
102 | \end{cfa} |
---|
103 | |
---|
104 | |
---|
105 | \section{Operators} |
---|
106 | 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}] |
---|
112 | 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); |
---|
126 | } |
---|
127 | \end{cfa} |
---|
128 | |
---|
129 | |
---|
130 | \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}] |
---|
137 | 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 |
---|
159 | \end{cfa} |
---|
160 | |
---|
161 | |
---|
162 | \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. |
---|
165 | |
---|
166 | \subsection{Parametric Polymorphism} |
---|
167 | \CFA provides parametric polymorphism in the form of @forall@, and @trait@s. |
---|
168 | A @forall@ takes in a set of types and a list of constraints. |
---|
169 | 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}] |
---|
175 | // sized() is a trait that means the type has a size |
---|
176 | forall( V & | sized(V) ) // type params for trait |
---|
177 | 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 | } |
---|
193 | } |
---|
194 | struct Vec1 { int x; }; |
---|
195 | void ?{}( Vec1 & this, Vec1 & other ) { this.x = other.x; } |
---|
196 | void ?{}( Vec1 & this, int x ) { this.x = x; } |
---|
197 | 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; } |
---|
200 | |
---|
201 | struct Vec2 { int x; int y; }; |
---|
202 | void ?{}( Vec2 & this, Vec2 & other ) { this.x = other.x; this.y = other.y; } |
---|
203 | void ?{}( Vec2 & this, int x ) { this.x = x; this.y = x; } |
---|
204 | 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 | |
---|
217 | \end{cfa} |
---|
218 | |
---|
219 | \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}] |
---|
225 | struct one_d { double x; }; |
---|
226 | struct two_d { |
---|
227 | inline one_d; |
---|
228 | double y; |
---|
229 | }; |
---|
230 | struct three_d { |
---|
231 | inline two_d; |
---|
232 | double z; |
---|
233 | }; |
---|
234 | double get_x( one_d & d ){ return d.x; } |
---|
235 | |
---|
236 | struct dog {}; |
---|
237 | struct dog_food { |
---|
238 | int count; |
---|
239 | }; |
---|
240 | 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 | |
---|