\chapter{Background} This chapter covers background material for C enumerations and \CFA features used in later discussion. \section{C} As mentioned in \VRef{s:Aliasing}, it is common for C programmers to ``believe'' there are three equivalent forms of named constants. \begin{clang} #define Mon 0 static const int Mon = 0; enum { Mon }; \end{clang} \begin{enumerate}[leftmargin=*] \item For @#define@, the programmer has to explicitly manage the constant name and value. Furthermore, these C preprocessor macro names are outside of the C type-system and can incorrectly change random text in a program. \item The same explicit management is true for the @const@ declaration, and the @const@ variable cannot appear in constant-expression locations, like @case@ labels, array dimensions,\footnote{ C allows variable-length array-declarations (VLA), so this case does work, but it fails in \CC, which does not support VLAs, unless it is \lstinline{g++}.} immediate oper\-ands of assembler instructions, and occupies storage. \begin{clang} $\$$ nm test.o 0000000000000018 r Mon \end{clang} \item Only the @enum@ form is managed by the compiler, is part of the language type-system, works in all C constant-expression locations, and normally does not occupy storage. \end{enumerate} \subsection{C \lstinline{const}} \label{s:Cconst} C can simulate the aliasing @const@ declarations \see{\VRef{s:Aliasing}}, with static and dynamic initialization. \begin{cquote} \begin{tabular}{@{}ll@{}} \multicolumn{1}{@{}c}{\textbf{static initialization}} & \multicolumn{1}{c@{}}{\textbf{dynamic initialization}} \\ \begin{clang} static const int one = 0 + 1; static const void * NIL = NULL; static const double PI = 3.14159; static const char Plus = '+'; static const char * Fred = "Fred"; static const int Mon = 0, Tue = Mon + 1, Wed = Tue + 1, Thu = Wed + 1, Fri = Thu + 1, Sat = Fri + 1, Sun = Sat + 1; \end{clang} & \begin{clang} void foo() { // auto scope only const int r = random() % 100; int va[r]; } \end{clang} \end{tabular} \end{cquote} However, statically initialized identifiers cannot appear in constant-expression contexts, \eg @case@. Dynamically initialized identifiers may appear in initialization and array dimensions in @g++@, which allows variable-sized arrays on the stack. Again, this form of aliasing is not an enumeration. \subsection{C Enumeration} \label{s:CEnumeration} The C enumeration has the following syntax~\cite[\S~6.7.2.2]{C11}. \begin{clang}[identifierstyle=\linespread{0.9}\it] $\it enum$-specifier: enum identifier$\(_{opt}\)$ { enumerator-list } enum identifier$\(_{opt}\)$ { enumerator-list , } enum identifier enumerator-list: enumerator enumerator-list , enumerator enumerator: enumeration-constant enumeration-constant = constant-expression \end{clang} The terms \emph{enumeration} and \emph{enumerator} used in this work \see{\VRef{s:Terminology}} come from the grammar. The C enumeration semantics are discussed using examples. \subsubsection{Type Name} \label{s:TypeName} An \emph{unnamed} enumeration is used to provide aliasing \see{\VRef{s:Aliasing}} exactly like a @const@ declaration in other languages. However, it is restricted to integral values. \begin{clang} enum { Size = 20, Max = 10, MaxPlus10 = Max + 10, @Max10Plus1@, Fred = -7 }; \end{clang} Here, the aliased constants are: 20, 10, 20, 21, and -7. Direct initialization is by a compile-time expression generating a constant value. Indirect initialization (without initializer, @Max10Plus1@) is called \newterm{auto-initialization}, where enumerators are assigned values from left to right, starting at zero or the next explicitly initialized constant, incrementing by @1@. Because multiple independent enumerators can be combined, enumerators with the same values can occur. The enumerators are rvalues, so assignment is disallowed. Finally, enumerators are \newterm{unscoped}, \ie enumerators declared inside of an @enum@ are visible (projected) outside into the enclosing scope of the @enum@ type. For unnamed enumerations, this semantic is required because there is no type name for scoped qualification. As noted, this kind of aliasing declaration is not an enumeration, even though it is declared using an @enum@ in C. While the semantics is misleading, this enumeration form matches with aggregate types: \begin{cfa} typedef struct @/* unnamed */@ { ... } S; struct @/* unnamed */@ { ... } x, y, z; $\C{// questionable}$ struct S { union @/* unnamed */@ { $\C{// unscoped fields}$ int i; double d ; char ch; }; }; \end{cfa} Hence, C programmers would expect this enumeration form to exist in harmony with the aggregate form. A \emph{named} enumeration is an enumeration: \begin{clang} enum @Week@ { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun }; \end{clang} and adopts the same semantics with respect to direct and auto intialization. For example, @Mon@ to @Wed@ are implicitly assigned with constants @0@--@2@, @Thu@ is explicitly set to constant @10@, and @Fri@ to @Sun@ are implicitly assigned with constants @11@--@13@. As well, initialization may occur in any order. \begin{clang} enum Week { Thu@ = 10@, Fri, Sat, Sun, Mon@ = 0@, Tue, Wed@,@ $\C{// terminating comma}$ }; \end{clang} Note, the comma in the enumerator list can be a terminator or a separator, allowing the list to end with a dangling comma.\footnote{ A terminating comma appears in other C syntax, \eg the initializer list.} This feature allow enumerator lines to be interchanged without moving a comma. Named enumerators are also unscoped. \subsubsection{Implementation} \label{s:CenumImplementation} In theory, a C enumeration \emph{variable} is an implementation-defined integral type large enough to hold all enumerator values. In practice, C defines @int@~\cite[\S~6.4.4.3]{C11} as the underlying type for enumeration variables, restricting initialization to integral constants, which have type @int@ (unless qualified with a size suffix). However, type @int@ is defined as: \begin{quote} A ``plain'' @int@ object has the natural size suggested by the architecture of the execution environment (large enough to contain any value in the range @INT_MIN@ to @INT_MAX@ as defined in the header @@).~\cite[\S~6.2.5(5)]{C11} \end{quote} However, @int@ means a 4 bytes on both 32/64-bit architectures, which does not seem like the ``natural'' size for a 64-bit architecture. Whereas, @long int@ means 4 bytes on a 32-bit and 8 bytes on 64-bit architectures, and @long long int@ means 8 bytes on both 32/64-bit architectures, where 64-bit operations are simulated on 32-bit architectures. \VRef[Figure]{f:gccEnumerationStorageSize} shows both @gcc@ and @clang@ partially ignore this specification and type the integral size of an enumerator based its initialization. Hence, initialization in the range @INT_MIN@..@INT_MAX@ results in a 4-byte enumerator, and outside this range the enumerator is 8 bytes. Note that @sizeof( typeof( IMin ) ) != sizeof( E )@, making the size of an enumerator different than is containing enumeration type, which seems inconsistent, \eg @sizeof( typeof( 3 ) ) == sizeof( int )@. \begin{figure} \begin{cfa} enum E { IMin = INT_MIN, IMax = INT_MAX, ILMin = LONG_MIN, ILMax = LONG_MAX, ILLMin = LLONG_MIN, ILLMax = LLONG_MAX }; int main() { printf( "%zd %zd\n%zd %zd\n%zd %d %d\n%zd %ld %ld\n%zd %ld %ld\n", sizeof(enum E), sizeof(typeof(IMin)), sizeof(int), sizeof(long int), sizeof(IMin), IMin, IMax, sizeof(ILMin), ILMin, ILMax, sizeof(ILLMin), ILLMin, ILLMax ); } 8 4 4 -2147483648 2147483647 8 -9223372036854775808 9223372036854775807 8 -9223372036854775808 9223372036854775807 \end{cfa} \caption{\lstinline{gcc}/\lstinline{clang} Enumeration Storage Size} \label{f:gccEnumerationStorageSize} \end{figure} \subsubsection{Usage} \label{s:Usage} C proves an implicit \emph{bidirectional} conversion between an enumeration and its integral type, and between two different enumerations. \begin{clang} enum Week week = Mon; $\C{// week == 0}$ week = Fri; $\C{// week == 11}$ int i = Sun; $\C{// implicit conversion to int, i == 13}$ @week = 10000;@ $\C{// UNDEFINED! implicit conversion to Week}$ enum Season { Spring, Summer, Fall, Winter }; @week = Winter;@ $\C{// UNDEFINED! implicit conversion to Week}$ \end{clang} While converting an enumerator to its underlying type is useful, the implicit conversion from the base or another enumeration type to an enumeration is a common source of error. Enumerators can appear in @switch@ and looping statements. \begin{cfa} enum Week { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; switch ( week ) { case Mon ... Fri: $\C{// gcc case range}$ printf( "weekday\n" ); case Sat: case Sun: printf( "weekend\n" ); } for ( enum Week day = Mon; day <= Sun; day += 1 ) { $\C{// step of 1}$ printf( "day %d\n", day ); // 0-6 } \end{cfa} For iterating using arithmetic to make sense, the enumerator values \emph{must} have a consecutive ordering with a fixed step between values. For example, a previous gap introduced by @Thu = 10@, results in iterating over the values 0--13, where values 3--9 are not @Week@ values. Note, it is the bidirectional conversion that allows incrementing @day@: @day@ is converted to @int@, integer @1@ is added, and the result is converted back to @Week@ for the assignment to @day@. For safety, \CC does not support the bidirectional conversion, and hence, an unsafe cast is necessary to increment @day@: @day = (Week)(day + 1)@. There is a C idiom to automatically compute the number of enumerators in an enumeration. \begin{cfa} enum E { A, B, C, D, @N@ }; // N == 4 for ( enum E e = A; e < @N@; e += 1 ) ... \end{cfa} Here, serendipitously the auto-incrementing counts the number of enumerators and puts the total into the last enumerator @N@. This @N@ is often used as the dimension for an array assocated with the enumeration. \begin{cfa} E array[@N@]; for ( enum E e = A; e < N; e += 1 ) { array[e] = e; } \end{cfa} However, for non-consecutive ordering and non-integral typed enumerations, \see{\VRef{f:EumeratorTyping}}, this idiom fails. This idiom is often used with another C idiom for matching companion information. For example, an enumeration may be linked with a companion array of printable strings. \begin{cfa} enum Integral_Type { chr, schar, uschar, sshort, ushort, sint, usint, ..., NO_OF_ITYPES }; char * Integral_Name[@NO_OF_ITYPES@] = { "char", "signed char", "unsigned char", "signed short int", "unsigned short int", "signed int", "unsigned int", ... }; enum Integral_Type @integral_type@ = ... printf( "%s\n", Integral_Name[@integral_type@] ); // human readable type name \end{cfa} However, the companion idiom results in the \emph{harmonizing} problem because an update to the enumeration @Integral_Type@ often requires a corresponding update to the companion array \snake{Integral_Name}. The requirement to harmonize is at best indicated by a comment before the enumeration. This issue is exacerbated if enumeration and companion array are in different translation units. \bigskip While C provides a true enumeration, it is restricted, has unsafe semantics, and does not provide useful/advanced enumeration features found in other programming languages. \section{\CFA} \CFA in \emph{not} an object-oriented programming-language, \ie functions cannot be nested in aggregate types, and hence, there is no \newterm{receiver} notation for calling functions, \eg @obj.method(...)@, where the first argument proceeds the call and becomes an implicit first (\lstinline[language=C++]{this}) parameter. The following sections provide short descriptions of \CFA features needed further in the thesis. Other \CFA features are presented in-situ with short explanations, or no explanation because the feature is obvious to C programmers. \subsection{Overloading} Overloading allows programmers to use the most meaningful names without fear of name clashes within a program or from external sources, like include files. \begin{quote} There are only two hard things in Computer Science: cache invalidation and naming things. --- Phil Karlton \end{quote} Experience from \CC and \CFA developers is that the type system implicitly and correctly disambiguates the majority of overloaded names, \ie it is rare to get an incorrect selection or ambiguity, even among hundreds of overloaded (variables and) functions. In many cases, a programmer has no idea there are name clashes, as they are silently resolved, simplifying the development process. Depending on the language, ambiguous cases are resolved using some form of qualification and/or casting. \subsection{Operator Overloading} Virtually all programming languages overload the arithmetic operators across the basic types using the number and type of parameters and returns. Like \CC, \CFA also allows these operators to be overloaded with user-defined types. The syntax for operator names uses the @'?'@ character to denote a parameter, \eg prefix and infix increment operators: @?++@, @++?@, and @?+?@. \begin{cfa} struct S { int i, j }; S @?+?@( S op1, S op2 ) { return (S){ op1.i + op2.i, op1.j + op2.j }; } S s1, s2; s1 = s1 @+@ s2; $\C[1.75in]{// infix call}$ s1 = @?+?@( s1, s2 ); $\C{// direct call}\CRT$ \end{cfa} The type system examines each call size and selects the best matching overloaded function based on the number and types of the arguments. If there are mixed-mode operands, @2 + 3.5@, the type system, like in C/\CC, attempts (safe) conversions, converting the argument type(s) to the parameter type(s). \subsection{Function Overloading} Both \CFA and \CC allow function names to be overloaded, as long as their prototypes differ in the number and type of parameters and returns. \begin{cfa} void f( void ); $\C[1.75in]{// (1): no parameter}$ void f( char ); $\C{// (2): overloaded on the number and parameter type}$ void f( int, int ); $\C{// (3): overloaded on the number and parameter type}$ f( 'A' ); $\C{// select (2)}\CRT$ \end{cfa} In this case, the name @f@ is overloaded depending on the number and parameter types. The type system examines each call size and selects the best match based on the number and types of the arguments. Here, there is a perfect match for the call, @f( 'A' )@ with the number and parameter type of function (2). Ada, Scala, and \CFA type-systems also use the return type in resolving a call, to pinpoint the best overloaded name. \begin{cfa} int f( void ); $\C[1.75in]{// (4); overloaded on return type}$ double f( void ); $\C{// (5); overloaded on return type}$ int i = f(); $\C{// select (4)}$ double d = f(); $\C{// select (5)}\CRT$ \end{cfa} \subsection{Variable Overloading} Unlike almost all programming languages, \CFA has variable overloading within a scope, along with shadow overloading in nested scopes. \begin{cfa} void foo( double d ); int v; $\C[1.75in]{// (1)}$ double v; $\C{// (2) variable overloading}$ foo( v ); $\C{// select (2)}$ { int v; $\C{// (3) shadow overloading}$ double v; $\C{// (4) and variable overloading}$ foo( v ); $\C{// select (4)}\CRT$ } \end{cfa} The \CFA type system simply treats overloaded variables as an overloaded function returning a value with no parameters. Hence, no significant effort is required to support this feature. \subsection{Constructor and Destructor} While \CFA in not object oriented, it adopts many language features commonly used in object-oriented languages; these features are independent from object-oriented programming. All objects in \CFA are initialized by @constructors@ \emph{after} allocation and de-initialized \emph{before} deallocation. \CC cannot have constructors for basic-types because they have no aggregate type \lstinline[language=C++]{struct/class} in which to insert a constructor definition. Like \CC, \CFA has multiple auto-generated constructors for every type. The prototype for the constructor/destructor are @void ?{}( T &, ... )@ and @void ^?{}( T &, ... )@, respectively. The first parameter is logically the \lstinline[language=C++]{this} or \lstinline[language=Python]{self} in other object-oriented languages, and implicitly passed. \VRef[Figure]{f:CFAConstructorDestructor} shows an example of creating and using a constructor and destructor. Both constructor and destructor can be explicitly called to reuse a variable. \begin{figure} \begin{cfa} struct Employee { char * name; double salary; }; void @?{}@( Employee & emp, char * nname, double nsalary ) with( emp ) { // auto qualification name = aalloc( sizeof(nname) ); strcpy( name, nname ); salary = nsalary; } void @^?{}@( Employee & emp ) { free( emp.name ); } { Employee emp = { "Sara Schmidt", 20.5 }; $\C{// initialize with implicit constructor call}$ ... // use emp ^?{}( emp ); $\C{// explicit de-initialize}$ ?{}( emp, "Jack Smith", 10.5 ); $\C{// explicit re-initialize}$ ... // use emp } $\C{// de-initialize with implicit destructor call}$ \end{cfa} \caption{\CFA Constructor and Destructor} \label{f:CFAConstructorDestructor} \end{figure} \subsection{Special Literals} The C constants @0@ and @1@ have special meaning. @0@ is the null pointer and used in conditional expressions, where @if ( p )@ is rewritten @if ( p != 0 )@; @1@ is an additive identity in unary operators @++@ and @--@. Aware of their significance, \CFA provides a special type @zero_t@ and @one_t@ for custom types. \begin{cfa} struct S { int i, j; }; void ?{}( S & this, @zero_t@ ) { this.i = 0; this.j = 0; } // zero_t, no parameter name allowed int ?@!=@?( S this, @zero_t@ ) { return this.i != 0 && this.j != 0; } S s = @0@; if ( s @!= 0@ ) ... \end{cfa} Similarity, for @one_t@. \begin{cfa} void ?{}( S & this, @one_t@ ) { this.i = 1; this.j = 1; } // one_t, no parameter name allowed S & ?++( S & this, @one_t@ ) { return (S){ this.i++, this.j++ }; } \end{cfa} \subsection{Polymorphic Functions} Polymorphic functions are the functions that apply to all types. \CFA provides \newterm{parametric polymorphism} written with the @forall@ clause. \begin{cfa} @forall( T )@ T identity( T v ) { return v; } identity( 42 ); \end{cfa} The @identity@ function accepts a value from any type as an argument and returns that value. At the call size, the type parameter @T@ is bounded to @int@ from the argument @42@. For polymorphic functions to be useful, the @forall@ clause needs \newterm{type assertion}s that restricts the polymorphic types it accepts. \begin{cfa} forall( T @| { void foo( T ); }@ ) void bar( T t ) { @foo( t );@ } struct S { ... } s; void foo( struct S ); bar( s ); \end{cfa} The assertion on @T@ restricts the range of types that can be manipulated by @bar@ to only those that have an implementation of @foo@ with the matching signature, allowing @bar@'s call to @foo@ in its body. Unlike templates in \CC, which are macro expansions at the call site, \CFA polymorphic functions are compiled, passing the call-site assertion functions as hidden parameters. \subsection{Trait} A @forall@ clause can assert many restrictions on multiple types. A common practice is to refactor the assertions into a named \newterm{trait}, similar to other lnaguages, like Go and Rust. \begin{cfa} forall(T) trait @Bird@ { int days_can_fly( T ); void fly( T ); }; forall( B | @Bird@( B ) ) void bird_fly( int days_since_born, B bird ) { if ( days_since_born > days_can_fly( bird )) fly( bird ); } struct Robin {} robin; int days_can_fly( Robin robin ) { return 23; } void fly( Robin robin ) {} bird_fly( 23, robin ); \end{cfa} Grouping type assertions into a named trait effectively creates a reusable interface for parametric-polymorphic types. \section{Expression Resolution} Overloading poses a challenge for all expression-resolution systems. Multiple overloaded names give multiple candidates at a call site, and a resolver must pick a \emph{best} match, where ``best'' is defined by a series of heuristics based on safety and programmer intuition/expectation. When multiple best matches exist, the resolution is ambiguous. The \CFA resolver attempts to identity a best candidate based on: first, the number of parameters and types, and second, when no exact match exists, the fewest implicit conversions and polymorphic variables. Finding an exact match is not discussed here, because the mechanism is fairly straightforward, even when the search space is large; only finding a non-exact match is discussed in detail. \subsection{Conversion Cost} \label{s:ConversionCost} Most programming languages perform some implicit conversions among basic types to facilitate mixed-mode arithmetic; otherwise, the program becomes littered with many explicit casts, which does not match with programmer expectation. C is an aggressive language as it provides conversions among almost all of the basic types, even when the conversion is potentially unsafe or not meaningful, \ie @float@ to @bool@. C defines the resolution pattern as ``usual arithmetic conversion''~\cite[\S~6.3.1.8]{C11}, in which C looks for a \newterm{common type} between operands, and converts one or both operands to the common type. Loosely defined, a common type is a the smallest type in terms of size of representation that both operands can be converted into without losing their precision, called a \newterm{widening} or \newterm{safe conversion}. \CFA generalizes ``usual arithmetic conversion'' to \newterm{conversion cost}. In the first design by Bilson~\cite{Bilson03}, conversion cost is a 3-tuple, @(unsafe, poly, safe)@ applied between each argument/parameter type, where: \begin{enumerate} \item @unsafe@ is the number of precision losing (\newterm{narrowing} conversions), \item @poly@ is the number of polymorphic function parameters, and \item @safe@ is sum of the degree of safe (widening) conversions. \end{enumerate} Sum of degree is a method to quantify C's integer and floating-point rank. Every pair of widening conversion types is assigned a \newterm{distance}, and distance between the two same type is 0. For example, the distance from @char@ to @int@ is 2, distance from @int@ to @long@ is 1, and distance from @int@ to @long long int@ is 2. This distance does not mirror C's rank system. For example, the rank of @char@ and @signed char@ are the same in C, but the distance from @char@ to @signed char@ is assigned 1. @safe@ cost is summing all pairs of argument to parameter safe conversion distances. Among the three costs in Bilson's model, @unsafe@ is the most significant cost and @safe@ is the least significant, with an implication that \CFA always choose a candidate with the lowest @unsafe@, if possible. For example, assume the overloaded function @foo@ is called with two @int@ parameter. The cost for every overloaded @foo@ has been list along: \begin{cfa} void foo( char, char ); $\C[2.5in]{// (1) (2, 0, 0)}$ void foo( char, int ); $\C{// (2) (1, 0, 0)}$ forall( T, V ) void foo( T, V ); $\C{// (3) (0, 2, 0)}$ forall( T ) void foo( T, T ); $\C{// (4) (0, 2, 0)}$ forall( T ) void foo( T, int ); $\C{// (5) (0, 1, 0)}$ void foo( long long, long ); $\C{// (6) (0, 0, 3)}$ void foo( long, long ); $\C{// (7) (0, 0, 2)}$ void foo( int, long ); $\C{// (8) (0, 0, 1)}$ int i, j; foo( i, j ); $\C{// convert j to long and call (8)}\CRT$ \end{cfa} The overloaded instances are ordered from the highest to the lowest cost, and \CFA select the last candidate (8). In the next iteration of \CFA, Schluntz and Aaron~\cite{Moss18} expanded conversion cost to a 7-tuple with 4 additional categories, @(unsafe, poly, safe, sign, vars, specialization, reference)@, with the following interpretations: \begin{itemize} \item \textit{Unsafe} \item \textit{Poly} \item \textit{Safe} \item \textit{Sign} is the number of sign/unsign variable conversion. \item \textit{Vars} is the number of polymorphics type variable. \item \textit{Specialization} is negative value of the number of type assertion. \item \textit{Reference} is number of reference-to-rvalue conversion. \end{itemize} The extended conversion-cost model looks for candidates that are more specific and less generic. @vars@ disambiguates @forall( T, V ) foo( T, V )@ and @forall( T ) void foo( T, T )@, where the extra type parameter @V@ makes is more generic. A more generic type means less constraints on its parameter types. \CFA favours candidates with more restrictions on polymorphism, so @forall( T ) void foo( T, T )@ has lower cost. @specialization@ is an arbitrary count-down value starting at zero. For every type assertion in @forall@ clause (no assertions in the above example), \CFA subtracts one from @specialization@. More type assertions means more constraints on argument types, making the function less generic. \CFA defines two special cost values: @zero@ and @infinite@. A conversion cost is @zero@ when argument and parameter has an exact match, and a conversion cost is @infinite@ when there is no defined conversion between two types. For example, the conversion cost from @int@ to a @struct S@ is @infinite@. In \CFA, the meaning of a C style cast is determined by its @Cast Cost@. For most cast expression resolution, a cast cost is equal to a conversion cost. Cast cost exists as an independent matrix for conversion that cannot happen implcitly, while being possible with an explicit cast. These conversions are often defined to have infinite conversion cost and non-infinite cast cost.