% ====================================================================== % ====================================================================== \chapter{Introduction to \CFA}\label{s:cfa} % ====================================================================== % ====================================================================== \section{Overview} The following serves as an introduction to \CFA. \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. Beyond C, it adds productivity features, extended libraries, an advanced type-system, and many control-flow/concurrency constructions. 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. \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. While \CFA is rich with interesting features, only the subset pertinent to this work is discussed. \section{References} References in \CFA are similar to references in \CC; however \CFA references are \emph{rebindable}, and support multi-level referencing. References in \CFA are a layer of syntactic sugar over pointers to reduce the number of ref/deref operations needed with pointer usage. Another difference is the use of @0p@ instead of C's @NULL@ or \CC's @nullptr@. Examples of references are shown in \VRef[Listing]{l:cfa_ref}. \begin{cfa}[caption={Example of \CFA references},label={l:cfa_ref}] int i = 2; int & ref_i = i; $\C{// declare ref to i}$ int * ptr_i = &i; $\C{// ptr to i}$ // address of ref_i is the same as address of i assert( &ref_i == ptr_i ); int && ref_ref_i = ref_i; $\C{// can have a ref to a ref}$ ref_i = 3; $\C{// set i to 3}$ int new_i = 4; // syntax to rebind ref_i (must cancel implicit deref) &ref_i = &new_i; $\C{// (\&*)ref\_i = \&new\_i; (sets underlying ptr)}$ \end{cfa} \section{Overloading}\label{s:Overloading} \CFA routines can be overloaded on parameter type, number of parameters, and \emph{return type}. Variables can also be overloaded on type, meaning that two variables can have the same name so long as they have different types. A routine or variable is disambiguated at each usage site via its type and surrounding expression context. A cast is used to disambiguate any conflicting usage. Examples of overloading are shown in \VRef[Listing]{l:cfa_overload}. \begin{cfa}[caption={Example of \CFA overloading},label={l:cfa_overload}] int foo() { sout | "A"; return 0;} int foo( int bar ) { sout | "B"; return 1; } int foo( double bar ) { sout | "C"; return 2; } double foo( double bar ) { sout | "D"; return 3; } void foo( double bar ) { sout | bar; } int main() { foo(); $\C{// prints A}$ foo( 0 ); $\C{// prints B}$ int foo = foo( 0.0 ); $\C{// prints C}$ double foo = foo( 0.0 ); $\C{// prints D}$ foo( foo ); $\C{// prints 3., where left-hand side of expression is void}$ } \end{cfa} \section{\lstinline{with} Statement} The \CFA @with@ statement is for exposing fields of an aggregate type within a scope, allowing field names without qualification. This feature is also implemented in Pascal~\cite{Pascal}. It can exist as a stand-alone statement or wrap a routine body to expose aggregate fields. Examples of the @with@ statement are shown in \VRef[Listing]{l:cfa_with}. \begin{cfa}[caption={Example of \CFA \lstinline{with} statement},label={l:cfa_with}] struct pair { double x, y; }; struct triple { int a, b, c; }; pair p; @with( p )@ { $\C{// stand-alone with}$ p.x = 6.28; p.y = 1.73; $\C{// long form}$ x = 6.28; y = 1.73; $\C{// short form}$ } void foo( triple t, pair p ) @with( t, p )@ { $\C{// routine with}$ t.a = 1; t.b = 2; t.c = 3; p.x = 3.14; p.y = 2.71; $\C{// long form}$ a = 1; b = 2; c = 3; x = 3.14; y = 2.71; $\C{// short form}$ } \end{cfa} \section{Operators} Operators can be overloaded in \CFA with operator routines. Operators in \CFA are named using an operator symbol and '@?@' to represent operands. Examples of \CFA operators are shown in \VRef[Listing]{l:cfa_operate}. \begin{cfa}[caption={Example of \CFA operators},label={l:cfa_operate}] struct coord { double x, y, z; }; coord ++@?@( coord & c ) with( c ) { $\C{// post increment}$ x++; y++; z++; return c; } coord @?@<=@?@( coord op1, coord op2 ) with( op1 ) { $\C{// ambiguous with both parameters}$ return (x * x + y * y + z * z) <= (op2.x * op2.x + op2.y * op2.y + op2.z * op2.z); } \end{cfa} \section{Constructors and Destructors} Constructors and destructors in \CFA are special operator routines used for creation and destruction of objects. The default constructor and destructor for a type are called implicitly upon creation and deletion, respectively. Examples of \CFA constructors and destructors are shown in \VRef[Listing]{l:cfa_ctor}. \begin{cfa}[caption={Example of \CFA constructors and destructors},label={l:cfa_ctor}] struct discrete_point { int x, y; }; void ?{}( discrete_point & this ) with(this) { $\C{// default constructor}$ [x, y] = 0; } void ?{}( discrete_point & this, int x, int y ) { $\C{// explicit constructor}$ this.[x, y] = [x, y]; } void ^?{}( discrete_point & this ) with(this) { $\C{// destructor}$ ?{}( this ); $\C{// reset by calling default constructor}$ } int main() { discrete_point x, y{}; $\C{// implicit call to default ctor, ?\{\}}$ discrete_point s = { 2, -4 }, t{ 4, 2 }; $\C{// explicit call to specialized ctor}$ } // ^t{}, ^s{}, ^y{}, ^x{} implicit calls in reverse allocation order \end{cfa} \section{Polymorphism}\label{s:poly} C supports limited polymorphism, often requiring users to implement polymorphism using a @void *@ (type erasure) approach. \CFA extends C with generalized overloading polymorphism (see \VRef{s:Overloading}), as well as, parametric polymorphism and limited containment inheritance. \subsection{Parametric Polymorphism} \CFA provides parametric polymorphism in the form of @forall@, and @trait@s. A @forall@ takes in a set of types and a list of constraints. The declarations that follow the @forall@ are parameterized over the types listed that satisfy the constraints. A list of @forall@ constraints can be refactored into a named @trait@ and reused in @forall@s. Examples of \CFA parametric polymorphism are shown in \VRef[Listing]{l:cfa_poly}. \begin{cfa}[caption={Example of \CFA parametric polymorphism},label={l:cfa_poly}] // sized() is a trait that means the type has a size forall( V & | sized(V) ) $\C{// type params for trait}$ trait vector_space { // dtor and copy ctor needed in constraints to pass by copy void ?{}( V &, V & ); $\C{// copy ctor for return}$ void ^?{}( V & ); $\C{// dtor}$ V ?+?( V, V ); $\C{// vector addition}$ V ?*?( int, V ); $\C{// scalar multiplication}$ }; forall( V & | vector_space( V ) ) { V get_inverse( V v1 ) { return -1 * v1; $\C{// can use ?*? routine defined in trait}$ } V add_and_invert( V v1, V v2 ) { return get_inverse( v1 + v2 ); $\C{// can use ?+? routine defined in trait}$ } } struct Vec1 { int x; }; void ?{}( Vec1 & this, Vec1 & other ) { this.x = other.x; } void ?{}( Vec1 & this, int x ) { this.x = x; } void ^?{}( Vec1 & this ) {} Vec1 ?+?( Vec1 v1, Vec1 v2 ) { v1.x += v2.x; return v1; } Vec1 ?*?( int c, Vec1 v1 ) { v1.x = v1.x * c; return v1; } struct Vec2 { int x; int y; }; void ?{}( Vec2 & this, Vec2 & other ) { this.x = other.x; this.y = other.y; } void ?{}( Vec2 & this, int x ) { this.x = x; this.y = x; } void ^?{}( Vec2 & this ) {} Vec2 ?+?( Vec2 v1, Vec2 v2 ) { v1.x += v2.x; v1.y += v2.y; return v1; } Vec2 ?*?( int c, Vec2 v1 ) { v1.x = v1.x * c; v1.y = v1.y * c; return v1; } int main() { Vec1 v1{ 1 }; $\C{// create Vec1 and call ctor}$ Vec2 v2{ 2 }; $\C{// create Vec2 and call ctor}$ // can use forall defined routines since types satisfy trait add_and_invert( get_inverse( v1 ), v1 ); add_and_invert( get_inverse( v2 ), v2 ); } \end{cfa} \subsection{Inheritance} Inheritance in \CFA is taken from Plan-9 C's containment inheritance. In \CFA, @struct@s can @inline@ another struct type to gain its fields and masquerade as that type. Examples of \CFA containment inheritance are shown in \VRef[Listing]{l:cfa_inherit}. \begin{cfa}[caption={Example of \CFA containment inheritance},label={l:cfa_inherit}] struct one_d { double x; }; struct two_d { @inline@ one_d; double y; }; struct three_d { @inline@ two_d; double z; }; double get_x( one_d & d ){ return d.x; } struct dog {}; struct dog_food { int count; }; struct pet { @inline@ dog; @inline@ dog_food; }; void pet_dog( dog & d ) { sout | "woof"; } void print_food( dog_food & f ) { sout | f.count; } int main() { one_d x; two_d y; three_d z; x.x = 1; y.x = 2; z.x = 3; get_x( x ); $\C{// returns 1;}$ get_x( y ); $\C{// returns 2;}$ get_x( z ); $\C{// returns 3;}$ pet p; p.count = 5; pet_dog( p ); $\C{// prints woof}$ print_food( p ); $\C{// prints 5}$ } \end{cfa} % Local Variables: % % tab-width: 4 % % End: %