# Changeset 5103d7a

Ignore:
Timestamp:
Apr 13, 2017, 10:30:54 AM (6 years ago)
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
Parents:
ffc9f5a
Message:

small fixups in tuples section

File:
1 edited

### Legend:

Unmodified
 rffc9f5a div_t qr = div( 13, 5 );                                        $\C{// return quotient/remainder aggregate}$ int q; double r = remquo( 13.5, 5.2, &q );                     $\C{// return return remainder, alias quotient}$ double r = remquo( 13.5, 5.2, &q );                     $\C{// return remainder, alias quotient}$ \end{lstlisting} @div@ aggregates the quotient/remainder in a structure, while @remquo@ aliases a parameter to an argument. Alternatively, a programming language can directly support returning multiple values, \eg in \CFA: \begin{lstlisting} [ int, int ] div( int num, int den ); [ double, double ] div( double num, double den ); int q, r; [ int, int ] div( int num, int den );           $\C{// return two integers}$ [ double, double ] div( double num, double den ); $\C{// return two doubles}$ int q, r;                                                                       $\C{// overload variable names}$ double q, r; [ q, r ] = div( 13, 5 );                                        $\C{// select appropriate div and q, r}$ \end{lstlisting} Clearly, this approach is straightforward to understand and use; therefore, why do most programming languages not support this obvious feature or provide it awkwardly? therefore, why do few programming languages support this obvious feature or provide it awkwardly? The answer is that there are complex consequences that cascade through multiple aspects of the language, especially the type-system. This section show these consequences and how \CFA deals with them. \subsection{Tuple Expressions} The addition of multiple-return-value (MRV) functions are useless without a syntax for accepting multiple values at the call-site. The addition of multiple-return-value functions (MRVF) are useless without a syntax for accepting multiple values at the call-site. The simplest mechanism for capturing the return values is variable assignment, allowing the values to be retrieved directly. As such, \CFA allows assigning multiple values from a function into multiple variables, using a square-bracketed list of lvalue expressions (as above), called a \emph{tuple}. However, functions also use \emph{composition} (nested calls), with the direct consequence that MRV functions must also support composition to be orthogonal with single-return-value (SRV) functions, \eg: However, functions also use \emph{composition} (nested calls), with the direct consequence that MRVFs must also support composition to be orthogonal with single-returning-value functions (SRVF), \eg: \begin{lstlisting} printf( "%d %d\n", div( 13, 5 ) );                      $\C{// return values seperated into arguments}$ bar( foo( 3 ), foo( 3 ) ); \end{lstlisting} The type-resolver only has the tuple return-types to resolve the call to @bar@ as the parameters are identical, which involves unifying the possible @foo@ functions with @bar@'s parameter list. The type-resolver only has the tuple return-types to resolve the call to @bar@ as the @foo@ parameters are identical, which involves unifying the possible @foo@ functions with @bar@'s parameter list. No combination of @foo@s are an exact match with @bar@'s parameters, so the resolver applies C conversions. The minimal cost is @bar( foo@$_1$@( 3 ), foo@$_2$@( 3 ) )@, giving (@int@, {\color{green}@int@}, @double@) to (@int@, {\color{green}@double@}, @double@) with one {\color{green}safe} (widening) conversion from @int@ to @double@ versus ({\color{red}@double@}, {\color{green}@int@}, {\color{green}@int@}) to ({\color{red}@int@}, {\color{green}@double@}, {\color{green}@double@}) with one {\color{red}unsafe} (narrowing) conversion from @double@ to @int@ and two safe conversions. \subsection{Tuple Variables} An important observation from function composition is that new variable names are not required to initialize parameters from an MRV function. As a consequence, \CFA allows declaration of \emph{tuple variables} that can be initialized from an MRV function, \eg: An important observation from function composition is that new variable names are not required to initialize parameters from an MRVF. \CFA also allows declaration of tuple variables that can be initialized from an MRVF, since it can be awkward to declare multiple variables of different types. As a consequence, \CFA allows declaration of \emph{tuple variables} that can be initialized from an MRVF, \eg: \begin{lstlisting} [ int, int ] qr = div( 13, 5 );                         $\C{// tuple-variable declaration and initialization}$ In the call to @g@, the values @y@ and @10@ are structured into a single argument of type @[int, int]@ to match the parameter type of @g@. Finally, in the call to @h@, @x@ is flattened to yield an argument list of length 3, of which the first component of @x@ is passed as the first parameter of @h@, and the second component of @x@ and @y@ are structured into the second argument of type @[int, int]@. The flexible structure of tuples permits a simple and expressive function call syntax to work seamlessly with both SRV and MRV functions, and with any number of arguments of arbitrarily complex structure. The flexible structure of tuples permits a simple and expressive function call syntax to work seamlessly with both SRVF and MRVF, and with any number of arguments of arbitrarily complex structure. Both kinds of tuple assignment have parallel semantics, so that each value on the left and right side is evaluated before any assignments occur. As a result, it is possible to swap the values in two variables without explicitly creating any temporary variables or calling a function, \eg, @[x, y] = [y, x]@. This semantics means mass assignment differs from C cascading assignment (\eg @a=b=c@) in that conversions are applied in each individual assignment, which prevents data loss from the chain of conversions that can happen during a cascading assignment. This semantics means mass assignment differs from C cascading assignment (\eg @a = b = c@) in that conversions are applied in each individual assignment, which prevents data loss from the chain of conversions that can happen during a cascading assignment. For example, @[y, x] = 3.14@ performs the assignments @y = 3.14@ and @x = 3.14@, yielding @y == 3.14@ and @x == 3@; whereas C cascading assignment @y = x = 3.14@ performs the assignments @x = 3.14@ and @y = x@, yielding @3@ in @y@ and @x@. Finally, tuple assignment is an expression where the result type is the type of the left-hand side of the assignment, just like all other assignment expressions in C. This example shows multiple, mass, and cascading assignment used in one expression: \begin{lstlisting} int a, b; double c, d; [void] f( [int, int] ); f( [c, a] = [b, d] = 1.5 );                                     $\C{// assignments in parameter list}$ This example shows mass, multiple, and cascading assignment used in one expression: \begin{lstlisting} void f( [int, int] ); f( [x, y] = z = 1.5 );                                          $\C{// assignments in parameter list}$ \end{lstlisting} struct B { int * k; short l; }; struct C { int x; A y; B z; } v; v.[x, y.[i, j], z.k]; v.[x, y.[i, j], z.k];                                           $\C{// [v.x, [v.y.i, v.y.j], v.z.k]}$ \end{lstlisting} \begin{lstlisting} forall(otype T, dtype U) void f( T x, U * y ); f([5, "hello"]); f( [5, "hello"] ); \end{lstlisting} where @[5, "hello"]@ is flattened, giving argument list @5, "hello"@, and @T@ binds to @int@ and @U@ binds to @const char@. Since @sum@$$_0$$ does not accept any arguments, it is not a valid candidate function for the call @sum(10, 20, 30)@. In order to call @sum@$$_1$$, @10@ is matched with @x@, and the argument resolution moves on to the argument pack @rest@, which consumes the remainder of the argument list and @Params@ is bound to @[20, 30]@. The process continues, @Params@ is bound to @[]@, requiring an assertion @int sum()@, which matchs @sum@$$_0$$ and terminates the recursion. The process continues, @Params@ is bound to @[]@, requiring an assertion @int sum()@, which matches @sum@$$_0$$ and terminates the recursion. Effectively, this algorithm traces as @sum(10, 20, 30)@ $\rightarrow$ @10 + sum(20, 30)@ $\rightarrow$ @10 + (20 + sum(30))@ $\rightarrow$ @10 + (20 + (30 + sum()))@ $\rightarrow$ @10 + (20 + (30 + 0))@.