source: doc/theses/fangren_yu_MMath/content1.tex @ 2325b57

Last change on this file since 2325b57 was c82dad4, checked in by Peter A. Buhr <pabuhr@…>, 7 weeks ago

more proofreading of intro and content1 chapters

  • Property mode set to 100644
File size: 37.1 KB
Line 
1\chapter{Recent Features Introduced to \CFA}
2\label{c:content1}
3
4This chapter discusses some recent additions to the \CFA language and their interactions with the type system.
5
6
7\section{Reference Types}
8
9Reference types were added to \CFA by Robert Schluntz and Aaron Moss~\cite{Moss18}.
10The \CFA reference type generalizes the \CC reference type (and its equivalent in other modern programming languages) by providing both mutable and immutable forms and cascading referencing and dereferencing.
11Specifically, \CFA attempts to extend programmer intuition about pointers to references.
12That is, use a pointer when its primary purpose is manipulating the address of storage, \eg a top/head/tail pointer or link field in a mutable data structure.
13Here, manipulating the pointer address is the primary operation, while dereferencing the pointer to its value is the secondary operation.
14For example, \emph{within} a data structure, \eg stack or queue, all operations involve pointer addresses and the pointer may never be dereferenced because the referenced object is opaque.
15Alternatively, use a reference when its primary purpose is to alias a value, \eg a function parameter that does not copy the argument (performance reason).
16Here, manipulating the value is the primary operation, while changing the pointer address is the secondary operation.
17Succinctly, if the address changes often, use a pointer;
18if the value changes often, use a reference.
19Note, \CC made its reference address immutable starting a \emph{belief} that immutability is a fundamental aspect of a reference's pointer.
20The results is asymmetry semantics between the pointer and reference.
21\CFA adopts a uniform policy between pointers and references where mutability is a separate property made at the declaration.
22
23The following examples shows how pointers and references are treated uniformly in \CFA.
24\begin{cfa}[numbers=left,numberblanklines=false]
25int x = 1, y = 2, z = 3;$\label{p:refexamples}$
26int * p1 = &x, ** p2 = &p1,  *** p3 = &p2,      $\C{// pointers to x}$
27        @&@ r1 = x,  @&&@ r2 = r1,   @&&&@ r3 = r2;     $\C{// references to x}$
28int * p4 = &z, & r4 = z;
29
30*p1 = 3; **p2 = 3; ***p3 = 3;                           $\C{// different ways to change x to 3}$
31 r1 =  3;       r2 = 3;         r3 = 3;                         $\C{// change x: implicit dereference *r1, **r2, ***r3}$
32**p3 = &y;      *p3 = &p4;                                              $\C{// change p1, p2}$
33// cancel implicit dereferences (&*)**r3, (&(&*)*)*r3, &(&*)r4
34@&@r3 = @&@y; @&&@r3 = @&&@r4;                          $\C{// change r1, r2}$
35\end{cfa}
36Like pointers, reference can be cascaded, \ie a reference to a reference, \eg @&& r2@.\footnote{
37\CC uses \lstinline{&&} for rvalue reference, a feature for move semantics and handling the \lstinline{const} Hell problem.}
38Usage of a reference variable automatically performs the same number of dereferences as the number of references in its declaration, \eg @r3@ becomes @***r3@.
39Finally, to reassign a reference's address needs a mechanism to stop the auto-referencing, which is accomplished by using a single reference to cancel all the auto-dereferencing, \eg @&r3 = &y@ resets @r3@'s address to point to @y@.
40\CFA's reference type (including multi-de/references) is powerful enough to describe the lvalue rules in C by types only.
41As a result, the \CFA type checker now works on just types without using the notion of lvalue in an expression.
42(\CFA internals still use lvalue for code generation purposes.)
43
44The current reference typing rules in \CFA are summarized as follows:
45\begin{enumerate}
46    \item For a variable $x$ with declared type $T$, the variable-expression $x$ has type reference to $T$, even if $T$ itself is a reference type.
47    \item For an expression $e$ with type $T\ \&_1...\&_n$, \ie $T$ followed by $n$ references, where $T$ is not a reference type, the expression $\&T$ (address of $T$) has type $T *$ followed by $n - 1$ references.
48    \item For an expression $e$ with type $T *\&_1...\&_n$, \ie $T *$  followed by $n$ references, the expression $* T$ (dereference $T$) has type $T$ followed by $n + 1$ references.
49        This rule is the reverse of the previous rule, such that address-of and dereference operators are perfect inverses.
50    \item When matching argument and parameter types at a function call, the number of references on the argument type is stripped off to match the number of references on the parameter type.\footnote{
51        \CFA handles the \lstinline{const} Hell problem by allowing rvalue expressions to be converted to reference values by implicitly creating a temporary variable, with some restrictions.
52        As well, there is a warning that the output nature of the reference is lost.
53        Hence, a single function handles \lstinline{const} and non-\lstinline{const} as constness is handled at the call site.}
54        In an assignment context, the left-hand-side operand-type is always reduced to a single reference.
55\end{enumerate}
56Under this ruleset, a type parameter is never bound to a reference type in a function-call context.
57\begin{cfa}
58forall( T ) void f( T & );
59int & x;
60f( x );  // implicit dereference
61\end{cfa}
62The call applies an implicit dereference once to @x@ so the call is typed @f( int & )@ with @T = int@, rather than with @T = int &@.
63
64As for a pointer type, a reference type may have qualifiers, where @const@ is most interesting.
65\begin{cfa}
66int x = 3; $\C{// mutable}$
67const int cx = 5; $\C{// immutable}$
68int * const cp = &x, $\C{// immutable pointer}$
69        & const cr = cx;
70const int * const ccp = &cx, $\C{// immutable value and pointer}$
71                        & const ccr = cx;
72// pointer
73*cp = 7;
74cp = &x; $\C{// error, assignment of read-only variable}$
75*ccp = 7; $\C{// error, assignment of read-only location}$
76ccp = &cx; $\C{// error, assignment of read-only variable}$
77// reference
78cr = 7;
79cr = &x; $\C{// error, assignment of read-only variable}$
80*ccr = 7; $\C{// error, assignment of read-only location}$
81ccr = &cx; $\C{// error, assignment of read-only variable}$
82\end{cfa}
83Interestingly, C does not give a warning/error if a @const@ pointer is not initialized, while \CC does.
84Hence, type @& const@ is similar to \CC reference, but \CFA does not preclude initialization with a non-variable address.
85For example, in system's programming, there are cases where an immutable address is initialized to a specific memory location.
86\begin{cfa}
87int & const mem_map = *0xe45bbc67@p@; $\C{// hardware mapped registers ('p' for pointer)}$
88\end{cfa}
89Finally, qualification is generalized across all pointer/reference declarations.
90\begin{cfa}
91const * const * const * const ccccp = ...
92const & const & const & const ccccr = ...
93\end{cfa}
94
95In the initial \CFA reference design, the goal was to make the reference type a \emph{real} data type \vs a restricted \CC reference, which is mostly used for choosing the argument-passing method, \ie by-value or by-reference.
96However, there is an inherent ambiguity for auto-dereferencing: every argument expression involving a reference variable can potentially mean passing the reference's value or address.
97Without any restrictions, this ambiguity limits the behaviour of reference types in \CFA polymorphic functions, where a type @T@ can bind to a reference or non-reference type.
98This ambiguity prevents the type system treating reference types the same way as other types in many cases even if type variables could be bound to reference types.
99The reason is that \CFA uses a common \emph{object trait}\label{p:objecttrait} (constructor, destructor and assignment operators) to handle passing dynamic concrete type arguments into polymorphic functions, and the reference types are handled differently in these contexts so they do not satisfy this common interface.
100
101Moreover, there is also some discrepancy in how the reference types are treated in initialization and assignment expressions.
102For example, in line 3 of the previous example code \see{\VPageref{p:refexamples}}:
103\begin{cfa}
104int @&@ r1 = x,  @&&@ r2 = r1,   @&&&@ r3 = r2; $\C{// references to x}$
105\end{cfa}
106each initialization expression is implicitly dereferenced to match the types, \eg @&x@, because an address is always required and a variable normally returns its value;
107\CC does the same implicit dereference when initializing its reference variables.
108For lines 6 and 9 of the previous example code:
109\begin{cfa}
110 r1 =  3;       r2 = 3;   r3 = 3;                               $\C{// change x: implicit dereference *r1, **r2, ***r3}$
111@&@r3 = @&@y; @&&@r3 = @&&@r4;                          $\C{// change r1, r2}$
112\end{cfa}
113there are no actual assignment operators defined for reference types that can be overloaded;
114instead, all reference assignments are handled by semantic actions in the type system.
115In fact, the reassignment of reference variables is setup internally to use the assignment operators for pointer types.
116Finally, there is an annoying issue (although purely syntactic) for setting a mutable reference to a specific address like null, @int & r1 = *0p@, which looks like dereferencing a null pointer.
117Here, the expression is rewritten as @int & r1 = &(*0p)@, like the variable dereference of @x@ above.
118However, the implicit @&@ needs to be cancelled for an address, which is done with the @*@, \ie @&*@ cancel each other, giving @0p@.
119Therefore, the dereferencing operation does not actually happen and the expression is translated into directly initializing the reference variable with the address.
120Note, the same explicit reference is used in \CC to set a reference variable to null.
121\begin{c++}
122int & ip = @*@(int *)nullptr;
123\end{c++}
124which is used in certain systems-programming situations.
125
126When generic types were introduced to \CFA~\cite{Moss19}, some thought was given to allow reference types as type arguments.
127\begin{cfa}
128forall( T ) struct vector { T t; }; $\C{// generic type}$
129vector( int @&@ ) vec; $\C{// vector of references to ints}$
130\end{cfa}
131While it is possible to write a reference type as the argument to a generic type, it is disallowed in assertion checking, if the generic type requires the object trait \see{\VPageref{p:objecttrait}} for the type argument (a fairly common use case).
132Even if the object trait can be made optional, the current type system often misbehaves by adding undesirable auto-dereference on the referenced-to value rather than the reference variable itself, as intended.
133Some tweaks are necessary to accommodate reference types in polymorphic contexts and it is unclear what can or cannot be achieved.
134Currently, there are contexts where \CFA programmer must use pointer types, giving up the benefits of auto-dereference operations and better syntax with reference types.
135
136
137\section{Tuple Types}
138
139The addition of tuples to \CFA can be traced back to the original design by David Till in \mbox{K-W C}~\cite{Till89,Buhr94a}, a predecessor project of \CFA.
140The primary purpose of tuples is to eliminate output parameters or creating an aggregate type to return multiple values from a function, called a multiple-value-returning (MVR) function.
141Traditionally, returning multiple values is accomplished via (in/)output parameters or packing the results in a structure.
142The following examples show these two techniques for a function returning three values.
143\begin{cquote}
144\begin{tabular}{@{}l@{\hspace{20pt}}l@{}}
145\begin{cfa}
146
147int foo( int &p2, int &p3 );  // in/out parameters
148int x, y = 3, z = 4;
149x = foo( y, z );  // return 3 values
150\end{cfa}
151&
152\begin{cfa}
153struct Ret { int x, y, z; };
154Ret foo( int p2, int p3 );  // multiple return values
155Ret ret = { .y = 3, .z = 4 };
156ret = foo( ret.y, ret.z );  // return 3 values
157\end{cfa}
158\end{tabular}
159\end{cquote}
160K-W C allows direct return of multiple values into a tuple.
161\begin{cfa}
162@[int, int, int]@ foo( int p2, int p3 );
163@[x, y, z]@ = foo( y, z );  // return 3 values into a tuple
164\end{cfa}
165Along with making returning multiple values a first-class feature, tuples were extended to simplify a number of other common context that normally require multiple statements and/or additional declarations, all of which reduces coding time and errors.
166\begin{cfa}
167[x, y, z] = 3; $\C[2in]{// x = 3; y = 3; z = 3, where types are different}$
168[x, y] = [y, x]; $\C{// int tmp = x; x = y; y = tmp;}$
169void bar( int, int, int );
170bar( foo( 3, 4 ) ); $\C{// int t0, t1, t2; [t0, t1, t2] = foo( 3, 4 ); bar( t0, t1, t2 );}$
171x = foo( 3, 4 )@.1@; $\C{//  int t0, t1, t2; [t0, t1, t2] = foo( 3, 4 ); x = t1;}\CRT$
172\end{cfa}
173For the call to @bar@, the three results (tuple value) from @foo@ are \newterm{flattened} into individual arguments.
174Flattening is how tuples interact with parameter and subscript lists, and with other tuples, \eg:
175\begin{cfa}
176[ [ x, y ], z, [a, b, c] ] = [2, [3, 4], foo( 3, 4) ]  $\C{// structured}$
177[ x, y, z, a, b, c] = [2, 3, 4, foo( 3, 4) ]  $\C{// flattened, where foo results are t0, t1, t2}$
178\end{cfa}
179Note, in most cases, a tuple is just compile-time syntactic-sugar for a number of individual assignments statements and possibly temporary variables.
180Only when returning a tuple from a function is there the notion of a tuple value.
181
182Overloading in the \CFA type-system must support complex composition of tuples and C type conversions using a costing scheme giving lower cost to widening conversions that do not truncate a value.
183\begin{cfa}
184[ int, int ] foo$\(_1\)$( int );                        $\C{// overloaded foo functions}$
185[ double ] foo$\(_2\)$( int );
186void bar( int, double, double );
187bar( @foo@( 3 ), @foo@( 3 ) );
188\end{cfa}
189The type resolver only has the tuple return types to resolve the call to @bar@ as the @foo@ parameters are identical, which involves unifying the flattened @foo@ return values with @bar@'s parameter list.
190However, no combination of @foo@s is an exact match with @bar@'s parameters;
191thus, the resolver applies C conversions to obtain a best match.
192The resulting minimal cost expression is @bar( foo@$_1$@( 3 ), foo@$_2$@( 3 ) )@, where the two possible coversions are (@int@, {\color{red}@int@}, @double@) to (@int@, {\color{red}@double@}, @double@) with a safe (widening) conversion from @int@ to @double@ versus ({\color{red}@double@}, {\color{red}@int@}, {\color{red}@int@}) to ({\color{red}@int@}, {\color{red}@double@}, {\color{red}@double@}) with one unsafe (narrowing) conversion from @double@ to @int@ and two safe conversions from @int@ to @double@.
193The programming language Go provides a similar but simplier tuple mechanism, as it does not have overloaded functions.
194
195K-W C also supported tuple variables, but with a strong distinction between tuples and tuple values/variables.
196\begin{quote}
197Note that tuple variables are not themselves tuples.
198Tuple variables reference contiguous areas of storage, in which tuple values are stored;
199tuple variables and tuple values are entities which appear during program execution.
200Tuples, on the other hand, are compile-time constructs;
201they are lists of expressions, whose values may not be stored contiguously.~\cite[p.~30]{Till89}
202\end{quote}
203Fundamentally, a tuple value/variable is just a structure (contiguous areas) with an alternate (tuple) interface.
204A tuple value/variable is assignable (like structures), its fields can be accessed using position rather than name qualification, and it can interact with regular tuples.
205\begin{cfa}
206[ int, int, int ] t1, t2;
207t1 = t2;                        $\C{// tuple assignment}$
208t1@.1@ = t2@.0@;        $\C{// position qualification}$
209int x, y, z;
210t1 = [ x, y, z ];       $\C{// interact with regular tuples}$
211[ x, y, z ] = t1;
212bar( t2 );                      $\C{// bar defined above}$
213\end{cfa}
214\VRef[Figure]{f:Nesting} shows The difference is nesting of structures and tuples.
215The left \CC nested-structure is named so it is not flattened.
216The middle C/\CC nested-structure is unnamed and flattened, causing an error because @i@ and @j@ are duplication names.
217The right \CFA nested tuple cannot be named and is flattened.
218C allows named nested-structures, but they have issues \see{\VRef{s:inlineSubstructure}}.
219Note, it is common in C to have an unnamed @union@ so its fields do not require qualification.
220
221\begin{figure}
222\setlength{\tabcolsep}{15pt}
223\begin{tabular}{@{}ll@{\hspace{90pt}}l@{}}
224\multicolumn{1}{c}{\CC} & \multicolumn{1}{c}{C/\CC} & \multicolumn{1}{c}{tuple} \\
225\begin{cfa}
226struct S {
227        struct @T@ { // not flattened
228                int i, j;
229        };
230        int i, j;
231};
232\end{cfa}
233&
234\begin{cfa}
235struct S2 {
236        struct ${\color{red}/* unnamed */}$ { // flatten
237                int i, j;
238        };
239        int i, j;
240};
241\end{cfa}
242&
243\begin{cfa}
244[
245        [ // flatten
246                1, 2
247        ]
248        1, 2
249]
250\end{cfa}
251\end{tabular}
252\caption{Nesting}
253\label{f:Nesting}
254\end{figure}
255
256The primary issues for tuples in the \CFA type system are polymorphism and conversions.
257Specifically, does it make sense to have a generic (polymorphic) tuple type, as is possible for a structure?
258\begin{cfa}
259forall( T, S ) [ T, S ] GT; // polymorphic tuple type
260GT( int, char ) @gt@;
261GT( int, double ) @gt@;
262@gt@ = [ 3, 'a' ]// select correct gt
263@gt@ = [ 3, 3.5 ];
264\end{cfa}
265and what is the cost model for C conversions across multiple values?
266\begin{cfa}
267gt = [ 'a', 3L ]// select correct gt
268\end{cfa}
269
270
271\section{Tuple Implementation}
272
273As noted, tradition languages manipulate multiple values by in/out parameters and/or structures.
274K-W C adopted the structure for tuple values or variables, and as needed, the fields are extracted by field access operations.
275As well, For the tuple-assignment implementation, the left-hand tuple expression is expanded into assignments of each component, creating temporary variables to avoid unexpected side effects.
276For example, the tuple value returned from @foo@ is a structure, and its fields are individually assigned to a left-hand tuple, @x@, @y@, @z@, or copied directly into a corresponding tuple variable.
277
278In the second implementation of \CFA tuples by Rodolfo Gabriel Esteves~\cite{Esteves04}, a different strategy is taken to handle MVR functions.
279The return values are converted to output parameters passed in by pointers.
280When the return values of a MVR function are directly used in an assignment expression, the addresses of the left-hand operands can be directly passed into the function;
281composition of MVR functions is handled by creating temporaries for the returns.
282For example, given a function returning two values:
283\begin{cfa}
284[int, int] gives_two() { int r1, r2; ... return [ r1, r2 ]; }
285int x, y;
286[x, y] = gives_two();
287\end{cfa}
288The Till K-W C implementation translates the program to:
289\begin{cfa}
290struct _tuple2 { int _0; int _1; }
291struct _tuple2 gives_two() { ... struct _tuple2 ret = { r1, r2 }, return ret; }
292int x, y;
293struct _tuple2 _tmp = gives_two();
294x = _tmp._0; y = _tmp._1;
295\end{cfa}
296while the Rodolfo implementation translates it to:
297\begin{cfa}
298void gives_two( int * r1, int * r2 ) { ... *r1 = ...; *r2 = ...; return; }
299int x, y;
300gives_two( &x, &y );
301\end{cfa}
302and inside the body of the function @gives_two@, the return statement is rewritten as assignments into the passed-in argument addresses.
303This implementation looks more concise, and in the case of returning values having nontrivial types, \eg aggregates, this implementation saves unnecessary copying.
304For example,
305\begin{cfa}
306[ x, y ] gives_two();
307int x, y;
308[ x, y ] = gives_two();
309\end{cfa}
310becomes
311\begin{cfa}
312void gives_two( int &, int & );
313int x, y;
314gives_two( x, y );
315\end{cfa}
316eliminiating any copying in or out of the call.
317The downside is indirection within @gives_two@ to access values, unless values get hoisted into registers for some period of time, which is common.
318
319Interestingly, in the third implementation of \CFA tuples by Robert Schluntz~\cite[\S~3]{Schluntz17}, the MVR functions revert back to structure based, where it remains in the current version of \CFA.
320The reason for the reversion was to have a uniform approach for tuple values/variables making tuples first-class types in \CFA, \ie allow tuples with corresponding tuple variables.
321This extension was possible, because in parallel with Schluntz's work, generic types were being added independently by Moss~\cite{Moss19}, and the tuple variables leveraged the same implementation techniques as the generic variables.
322\PAB{I'm not sure about the connection here. Do you have an example of what you mean?}
323
324However, after experience gained building the \CFA runtime system, making tuple-types first-class seems to add little benefit.
325The main reason is that tuples usages are largely unstructured,
326\begin{cfa}
327[int, int] foo( int, int ); $\C[2in]{// unstructured function}$
328typedef [int, int] Pair; $\C{// tuple type}$
329Pair bar( Pair ); $\C{// structured function}$
330int x = 3, y = 4;
331[x, y] = foo( x, y ); $\C{// unstructured call}$
332Pair ret = [3, 4]; $\C{// tuple variable}$
333ret = bar( ret ); $\C{// structured call}\CRT$
334\end{cfa}
335Basically, creating the tuple-type @Pair@ is largely equivalent to creating a @struct@ type, and creating more types and names defeats the simplicity that tuples are trying to achieve.
336Furthermore, since operator overloading in \CFA is implemented by treating operators as overloadable functions, tuple types are very rarely used in a structured way.
337When a tuple-type expression appears in a function call (except assignment expressions, which are handled differently by mass- or multiple-assignment expansions), it is always flattened, and the tuple structure of function parameter is not considered a part of the function signatures.
338For example,
339\begin{cfa}
340void f( int, int );
341void f( [int, int] );
342f( 3, 4 )// ambiguous call
343\end{cfa}
344the two prototypes for @foo@ have the same signature (a function taking two @int@s and returning nothing), and therefore invalid overloads.
345Note, the ambiguity error occurs at the call rather than at the second declaration of @f@, because it is possible to have multiple equivalent prototype definitions of a function.
346Furthermore, ordinary polymorphic type-parameters are not allowed to have tuple types.
347\begin{cfa}
348forall( T ) T foo( T );
349int x, y, z;
350[x, y, z] = foo( [x, y, z] )// substitute tuple type for T
351\end{cfa}
352Without this restriction, the expression resolution algorithm can create too many argument-parameter matching options.
353For example, with multiple type parameters,
354\begin{cfa}
355forall( T, U ) void f( T, U );
356f( [1, 2, 3, 4] );
357\end{cfa}
358the call to @f@ can be interpreted as @T = [1]@ and @U = [2, 3, 4, 5]@, or @T = [1, 2]@ and @U = [3, 4, 5]@, and so on.
359The restriction ensures type checking remains tractable and does not take too long to compute.
360Therefore, tuple types are never present in any fixed-argument function calls.
361
362Finally, a type-safe variadic argument signature was added by Robert Schluntz~\cite[\S~4.1.2]{Schluntz17} using @forall@ and a new tuple parameter-type, denoted by the keyword @ttype @ in Schluntz's implementation, but changed to the ellipsis syntax similar to \CC's template parameter pack.
363For C variadics, \eg @va_list@, the number and types of the arguments must be conveyed in some way, \eg @printf@ uses a format string indicating the number and types of the arguments.
364\VRef[Figure]{f:CVariadicMaxFunction} shows an $N$ argument @maxd@ function using the C untyped @va_list@ interface.
365In the example, the first argument is the number of following arguments, and the following arguments are assumed to be @double@;
366looping is used to traverse the argument pack from left to right.
367The @va_list@ interface is walking up the stack (by address) looking at the arguments pushed by the caller.
368(Magic knowledge is needed for arguments pushed using registers.)
369
370\begin{figure}
371\begin{cfa}
372double maxd( int @count@, ... ) {
373    double max = 0;
374    va_list args;
375    va_start( args, count );
376    for ( int i = 0; i < count; i += 1 ) {
377        double num = va_arg( args, double );
378        if ( num > max ) max = num;
379    }
380    va_end(args);
381    return max;
382}
383printf( "%g\n", maxd( @4@, 25.0, 27.3, 26.9, 25.7 ) );
384\end{cfa}
385\caption{C Variadic Maximum Function}
386\label{f:CVariadicMaxFunction}
387\end{figure}
388
389There are two common patterns for using the variadic functions in \CFA.
390\begin{enumerate}[leftmargin=*]
391\item
392Argument forwarding to another function, \eg:
393\begin{cfa}
394forall( T *, TT ... | { @void ?{}( T &, TT );@ } ) // constructor assertion
395T * new( TT tp ) { return ((T *)malloc())@{@ tp @}@; }  // call constructor on storage
396\end{cfa}
397Note, the assertion on @T@ requires it to have a constructor @?{}@.
398The function @new@ calls @malloc@ to obtain storage and then invokes @T@'s constructor passing the tuple pack by flattening it over the constructor's arguments, \eg:
399\begin{cfa}
400struct S { int i, j; };
401void ?{}( S & s, int i, int j ) { s.[ i, j ] = [ i, j ]; }  // constructor
402S * sp = new( 3, 4 )// flatten [3, 4] into call ?{}( 3, 4 );
403\end{cfa}
404\item
405Structural recursion for processing the argument-pack values one at a time, \eg:
406\begin{cfa}
407forall( T | { int ?>?( T, T ); } )
408T max( T v1, T v2 ) { return v1 > v2 ? v1 : v2; }
409$\vspace{-10pt}$
410forall( T, TT ... | { T max( T, T ); T max( TT ); } )
411T max( T arg, TT args ) { return max( arg, max( args ) ); }
412\end{cfa}
413The first non-recursive @max@ function is the polymorphic base-case for the recursion, \ie, find the maximum of two identically typed values with a greater-than (@>@) operator.
414The second recursive @max@ function takes two parameters, a @T@ and a @TT@ tuple pack, handling all argument lengths greater than two.
415The recursive function computes the maximum for the first argument and the maximum value of the rest of the tuple pack.
416The call of @max@ with one argument is the recursive call, where the tuple pack is converted into two arguments by taking the first value (lisp @car@) from the tuple pack as the first argument (flattening) and the remaining pack becomes the second argument (lisp @cdr@).
417The recursion stops when the argument pack is empty.
418For example, @max( 2, 3, 4 )@ matches with the recursive function, which performs @return max( 2, max( [3, 4] ) )@ and one more step yields @return max( 2, max( 3, 4 ) )@, so the tuple pack is empty.
419\end{enumerate}
420
421As an aside, polymorphic functions are precise with respect to their parameter types, \eg @max@ states all argument values must be the same type, which logically makes sense.
422However, this precision precludes normal C conversions among the base types, \eg, this mix-mode call @max( 2h, 2l, 3.0f, 3.0ld )@ fails because the types are not the same.
423Unfortunately, this failure violates programmer intuition because there are specialized two-argument non-polymorphic versions of @max@ that work, \eg @max( 3, 3.5 )@.
424Allowing C conversions for polymorphic types will require a significant change to the type resolver.
425
426Currently in \CFA, variadic polymorphic functions are the only place tuple types are used.
427And because \CFA compiles polymorphic functions versus template expansion, many wrapper functions are generated to implement both user-defined generic-types and polymorphism with variadics.
428Fortunately, the only permitted operations on polymorphic function parameters are given by the list of assertion (trait) functions.
429Nevertheless, this small set of functions eventually need to be called with flattened tuple arguments.
430Unfortunately, packing the variadic arguments into a rigid @struct@ type and generating all the required wrapper functions is significant work and largely wasted because most are never called.
431Interested readers can refer to pages 77-80 of Robert Schluntz's thesis to see how verbose the translator output is to implement a simple variadic call with 3 arguments.
432As the number of arguments increases, \eg a call with 5 arguments, the translator generates a concrete @struct@ types for a 4-tuple and a 3-tuple along with all the polymorphic type data for them.
433An alternative approach is to put the variadic arguments into an array, along with an offset array to retrieve each individual argument.
434This method is similar to how the C @va_list@ object is used (and how \CFA accesses polymorphic fields in a generic type), but the \CFA variadics generate the required type information to guarantee type safety.
435For example, given the following heterogeneous, variadic, typed @print@ and usage.
436\begin{cquote}
437\begin{tabular}{@{}ll@{}}
438\begin{cfa}
439forall( T, TT ... | { void print( T ); void print( TT ); } )
440void print( T arg , TT rest ) {
441        print( arg );
442        print( rest );
443}
444\end{cfa}
445&
446\begin{cfa}
447void print( int i ) { printf( "%d ", i ); }
448void print( double d ) { printf( "%g ", d ); }
449... // other types
450int i = 3 ; double d = 3.5;
451print( i, d );
452\end{cfa}
453\end{tabular}
454\end{cquote}
455it would look like the following using the offset-array implementation approach.
456\begin{cfa}
457void print( T arg, char * _data_rest, size_t * _offset_rest ) {
458        print( arg );
459        print( *((typeof rest.0)*) _data_rest,  $\C{// first element of rest}$
460                  _data_rest + _offset_rest[0]$\C{// remainder of data}$
461                  _offset_rest + 1)$\C{// remainder of offset array}$
462}
463\end{cfa}
464where the fixed-arg polymorphism for @T@ can be handled by the standard @void *@-based \CFA polymorphic calling conventions, and the type information can all be deduced at the call site.
465Note, the variadic @print@ supports heterogeneous types because the polymorphic @T@ is not returned (unlike variadic @max@), so there is no cascade of type relationships.
466
467Turning tuples into first-class values in \CFA does have a few benefits, namely allowing pointers to tuples and arrays of tuples to exist.
468However, it seems unlikely that these types have realistic use cases that cannot be achieved without them.
469And having a pointer-to-tuple type potentially forbids the simple offset-array implementation of variadic polymorphism.
470For example, in the case where a type assertion requests the pointer type @TT *@ in the above example, it forces the tuple type to be a @struct@, and thus incurring a high cost.
471My conclusion is that tuples should not be structured (first-class), rather they should be unstructured.
472This agrees with Rodolfo's original describes
473\begin{quote}
474As such, their [tuples] use does not enforce a particular memory layout, and in particular, does not guarantee that the components of a tuple occupy a contiguous region of memory.~\cite[pp.~74--75]{Esteves04}
475\end{quote}
476allowing the simplified implementations for MVR and variadic functions.
477
478Finally, a missing feature for tuples is using an MVR in an initialization context.
479Currently, this feature is \emph{only} possible when declaring a tuple variable.
480\begin{cfa}
481[int, int] ret = gives_two()$\C{// no constructor call (unstructured)}$
482Pair ret = gives_two()$\C{// constructor call (structured)}$
483\end{cfa}
484However, this forces the programer to use a tuple variable and possibly a tuple type to support a constructor, when they actually want separate variables with separate constructors.
485And as stated previously, type variables (structured tuples) are rare in general \CFA programming so far.
486To address this issue, while retaining the ability to leverage constructors, the following new tuple-like declaration syntax is proposed.
487\begin{cfa}
488[ int x, int y ] = gives_two();
489\end{cfa}
490where the semantics is:
491\begin{cfa}
492T t0, t1;
493[ t0, t1 ] = gives_two();
494T x = t0// constructor call
495T y = t1// constructor call
496\end{cfa}
497and the implementation performs as much copy elision as possible.
498
499
500\section{\lstinline{inline} Substructure}
501\label{s:inlineSubstructure}
502
503As mentioned \see{\VRef[Figure]{f:Nesting}}, C allows an anonymous aggregate type (@struct@ or @union@) to be embedded (nested) within another one, \eg a tagged union.
504\begin{cfa}
505struct S {
506        unsigned int tag;
507        union { $\C{// anonymous nested aggregate}$
508                int x;  double y;  char z;
509        };
510} s;
511\end{cfa}
512The @union@ field-names are hoisted into the @struct@, so there is direct access, \eg @s.x@;
513hence, field names must be unique.
514For a nested anonymous @struct@, both field names and values are hoisted.
515\begin{cquote}
516\begin{tabular}{@{}l@{\hspace{35pt}}l@{}}
517original & rewritten \\
518\begin{cfa}
519struct S {
520        struct { int i, j; };
521        struct { int k, l; };
522};
523\end{cfa}
524&
525\begin{cfa}
526struct S {
527        int i, j;
528        int k, l;
529};
530\end{cfa}
531\end{tabular}
532\end{cquote}
533
534As an aside, C nested \emph{named} aggregates behave in a (mysterious) way because the nesting is allowed but there is no ability to use qualification to access an inner type, like the \CC type operator `@::@'.
535\emph{In fact, all named nested aggregates are hoisted to global scope, regardless of the nesting depth.}
536\begin{cquote}
537\begin{tabular}{@{}l@{\hspace{35pt}}l@{}}
538original & rewritten \\
539\begin{cfa}
540struct S {
541        struct T {
542                int i, j;
543        };
544        struct U {
545                int k, l;
546        };
547};
548\end{cfa}
549&
550\begin{cfa}
551struct T {
552        int i, j;
553};
554struct U {
555        int k, l;
556};
557struct S {
558};
559\end{cfa}
560\end{tabular}
561\end{cquote}
562Hence, the possible accesses are:
563\begin{cfa}
564struct S s; // s cannot access any fields
565struct T t;  t.i;  t.j;
566struct U u;  u.k;  u.l;
567\end{cfa}
568and the hoisted type names can clash with global types names.
569For good reasons, \CC chose to change this semantics:
570\begin{cquote}
571\begin{description}[leftmargin=*,topsep=0pt,itemsep=0pt,parsep=0pt]
572\item[Change:] A struct is a scope in C++, not in C.
573\item[Rationale:] Class scope is crucial to C++, and a struct is a class.
574\item[Effect on original feature:] Change to semantics of well-defined feature.
575\item[Difficulty of converting:] Semantic transformation.
576\item[How widely used:] C programs use @struct@ extremely frequently, but the change is only noticeable when @struct@, enumeration, or enumerator names are referred to outside the @struct@.
577The latter is probably rare.
578\end{description}
579\hfill ISO/IEC 14882:1998 (\CC Programming Language Standard)~\cite[C.1.2.3.3]{ANSI98:C++}
580\end{cquote}
581However, there is no syntax to access from a variable through a type to a field.
582\begin{cfa}
583struct S s;  @s::T@.i;  @s::U@.k;
584\end{cfa}
585\CFA chose to adopt the \CC non-compatible change for nested types, since \CC's change has already forced certain coding changes in C libraries that must be parsed by \CC.
586
587% https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html
588
589A polymorphic extension to nested aggregates appears in the Plan-9 C dialect, used in the Bell Labs' Plan-9 research operating system.
590The feature is called \newterm{unnamed substructures}~\cite[\S~3.3]{Thompson90new}, which continues to be supported by @gcc@ and @clang@ using the extension (@-fplan9-extensions@).
591The goal is to provided the same effect of the nested aggregate with the aggregate type defined elsewhere, which requires it be named.
592\begin{cfa}
593union U {  $\C{// unnested named}$
594        int x;  double y;  char z;
595} u;
596struct W {
597        int i;  double j;  char k;
598} w;
599struct S {
600        @struct W;@  $\C{// Plan-9 substructure}$
601        unsigned int tag;
602        @union U;@  $\C{// Plan-9 substructure}$
603} s;
604\end{cfa}
605Note, the position of the substructure is normally unimportant, unless there is some form of memory or @union@ overlay.
606Like the anonymous nested types, the aggregate field names are hoisted into @struct S@, so there is direct access, \eg @s.x@ and @s.i@.
607However, like the implicit C hoisting of nested structures, the field names must be unique and the type names are now at a different scope level, unlike type nesting in \CC.
608In addition, a pointer to a structure is automatically converted to a pointer to an anonymous field for assignments and function calls, providing containment inheritance with implicit subtyping, \ie @U@ $\subset$ @S@ and @W@ $\subset$ @S@.
609For example:
610\begin{cfa}
611void f( union U * u );
612void g( struct W * );
613union U * up;
614struct W * wp;
615struct S * sp;
616up = sp; $\C{// assign pointer to U in S}$
617wp = sp; $\C{// assign pointer to W in S}$
618f( &s ); $\C{// pass pointer to U in S}$
619g( &s ); $\C{// pass pointer to W in S}$
620\end{cfa}
621
622\CFA extends the Plan-9 substructure by allowing polymorphism for values and pointers.
623The extended substructure is denoted using @inline@, allowing backwards compatibility to existing Plan-9 features.
624\begin{cfa}
625struct S {
626        @inline@ W;  $\C{// extended Plan-9 substructure}$
627        unsigned int tag;
628        @inline@ U;  $\C{// extended Plan-9 substructure}$
629} s;
630\end{cfa}
631Note, like \CC, \CFA allows optional prefixing of type names with their kind, \eg @struct@, @union@, and @enum@, unless there is ambiguity with variable names in the same scope.
632The following shows both value and pointer polymorphism.
633\begin{cfa}
634void f( U, U * ); $\C{// value, pointer}$
635void g( W, W * ); $\C{// value, pointer}$
636U u, * up;
637S s, * sp;
638W w, * wp;
639u = s;  up = sp; $\C{// value, pointer}$
640w = s;  wp = sp; $\C{// value, pointer}$
641f( s, &s ); $\C{// value, pointer}$
642g( s, &s ); $\C{// value, pointer}$
643\end{cfa}
644
645In general, non-standard C features (@gcc@) do not need any special treatment, as they are directly passed through to the C compiler.
646However, the Plan-9 semantics allow implicit conversions from the outer type to the inner type, which means the \CFA type resolver must take this information into account.
647Therefore, the \CFA translator must implement the Plan-9 features and insert necessary type conversions into the translated code output.
648In the current version of \CFA, this is the only kind of implicit type conversion other than the standard C conversions.
649
650Since variable overloading is possible in \CFA, \CFA's implementation of Plan-9 polymorphism allows duplicate field names.
651When an outer field and an embedded field have the same name and type, the inner field is shadowed and cannot be accessed directly by name.
652While such definitions are allowed, duplicate field names is not good practice in general and should be avoided if possible.
653Plan-9 fields can be nested, and a struct definition can contain multiple Plan-9 embedded fields.
654In particular, the \newterm{diamond pattern}~\cite[\S~6.1]{Stroustrup89}\cite[\S~4]{Cargill91}  can occur and result in a nested field to be embedded twice.
655\begin{cfa}
656struct A { int x; };
657struct B { inline A; };
658struct C { inline A; };
659struct D {
660        inline B;
661        inline C;
662};
663D d;
664\end{cfa}
665In the above example, the expression @d.x@ becomes ambiguous, since it can refer to the indirectly embedded field either from @B@ or from @C@.
666It is still possible to disambiguate the expression by first casting the outer struct to one of the directly embedded type, such as @((B)d).x@.
Note: See TracBrowser for help on using the repository browser.