Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/rob_thesis/tuples.tex

    r0eb18557 rf92aa32  
    7070Furthermore, while many C routines that accept pointers are designed so that it is safe to pass @NULL@ as a parameter, there are many C routines that are not null-safe.
    7171On a related note, C does not provide a standard mechanism to state that a parameter is going to be used as an additional return value, which makes the job of ensuring that a value is returned more difficult for the compiler.
    72 Interestingly, there is a subtle bug in the previous example, in that @ret_ch@ is never assigned for a string that does not contain any letters, which can lead to undefined behaviour.
    73 In this particular case, it turns out that the frequency return value also doubles as an error code, where a frequency of 0 means the character return value should be ignored.
    74 Still, not every routine with multiple return values should be required to return an error code, and error codes are easily ignored, so this is not a satisfying solution.
     72There is a subtle bug in the previous example, in that @ret_ch@ is never assigned for a string that does not contain any letters, which can lead to undefined behaviour.
    7573As with the previous approach, this technique can simulate multiple return values, but in practice it is verbose and error prone.
    7674
     
    8684  char freqs [26] = { 0 };
    8785  int ret_freq = 0;
    88   char ret_ch = 'a';  // arbitrary default value for consistent results
     86  char ret_ch = 'a';
    8987  for (int i = 0; str[i] != '\0'; ++i) {
    9088    if (isalpha(str[i])) {        // only count letters
     
    10098}
    10199\end{cfacode}
    102 This approach provides the benefits of compile-time checking for appropriate return statements as in aggregation, but without the required verbosity of declaring a new named type, which precludes the bug seen with out-parameters.
     100This approach provides the benefits of compile-time checking for appropriate return statements as in aggregation, but without the required verbosity of declaring a new named type, which precludes the bug seen with out parameters.
    103101
    104102The addition of multiple-return-value functions necessitates a syntax for accepting multiple values at the call-site.
     
    210208For the call to @g@, the values @y@ and @10@ are structured into a single argument of type @[int, int]@ to match the type of the parameter of @g@.
    211209Finally, in the call to @h@, @y@ 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]@.
    212 The flexible structure of tuples permits a simple and expressive function-call syntax to work seamlessly with both single- and multiple-return-value functions, and with any number of arguments of arbitrarily complex structure.
     210The flexible structure of tuples permits a simple and expressive function call syntax to work seamlessly with both single- and multiple-return-value functions, and with any number of arguments of arbitrarily complex structure.
    213211
    214212In \KWC \cite{Buhr94a,Till89}, a precursor to \CFA, there were 4 tuple coercions: opening, closing, flattening, and structuring.
    215213Opening coerces a tuple value into a tuple of values, while closing converts a tuple of values into a single tuple value.
    216 Flattening coerces a nested tuple into a flat tuple, \ie it takes a tuple with tuple components and expands it into a tuple with only non-tuple components.
    217 Structuring moves in the opposite direction, \ie it takes a flat tuple value and provides structure by introducing nested tuple components.
     214Flattening coerces a nested tuple into a flat tuple, i.e. it takes a tuple with tuple components and expands it into a tuple with only non-tuple components.
     215Structuring moves in the opposite direction, i.e. it takes a flat tuple value and provides structure by introducing nested tuple components.
    218216
    219217In \CFA, the design has been simplified to require only the two conversions previously described, which trigger only in function call and return situations.
     
    260258A mass assignment assigns the value $R$ to each $L_i$.
    261259For a mass assignment to be valid, @?=?(&$L_i$, $R$)@ must be a well-typed expression.
    262 These semantics differ from C cascading assignment (\eg @a=b=c@) in that conversions are applied to $R$ in each individual assignment, which prevents data loss from the chain of conversions that can happen during a cascading assignment.
     260These semantics differ from C cascading assignment (e.g. @a=b=c@) in that conversions are applied to $R$ in each individual assignment, which prevents data loss from the chain of conversions that can happen during a cascading assignment.
    263261For example, @[y, x] = 3.14@ performs the assignments @y = 3.14@ and @x = 3.14@, which results in the value @3.14@ in @y@ and the value @3@ in @x@.
    264262On the other hand, the C cascading assignment @y = x = 3.14@ performs the assignments @x = 3.14@ and @y = x@, which results in the value @3@ in @x@, and as a result the value @3@ in @y@ as well.
     
    276274These semantics allow cascading tuple assignment to work out naturally in any context where a tuple is permitted.
    277275These semantics are a change from the original tuple design in \KWC \cite{Till89}, wherein tuple assignment was a statement that allows cascading assignments as a special case.
    278 Restricting tuple assignment to statements was an attempt to to fix what was seen as a problem with side-effects, wherein assignment can be used in many different locations, such as in function-call argument position.
     276Restricting tuple assignment to statements was an attempt to to fix what was seen as a problem with assignment, wherein it can be used in many different locations, such as in function-call argument position.
    279277While permitting assignment as an expression does introduce the potential for subtle complexities, it is impossible to remove assignment expressions from \CFA without affecting backwards compatibility.
    280278Furthermore, there are situations where permitting assignment as an expression improves readability by keeping code succinct and reducing repetition, and complicating the definition of tuple assignment puts a greater cognitive burden on the user.
     
    291289\end{cfacode}
    292290The tuple expression begins with a mass assignment of @1.5@ into @[b, d]@, which assigns @1.5@ into @b@, which is truncated to @1@, and @1.5@ into @d@, producing the tuple @[1, 1.5]@ as a result.
    293 That tuple is used as the right side of the multiple assignment (\ie, @[c, a] = [1, 1.5]@) that assigns @1@ into @c@ and @1.5@ into @a@, which is truncated to @1@, producing the result @[1, 1]@.
     291That tuple is used as the right side of the multiple assignment (i.e., @[c, a] = [1, 1.5]@) that assigns @1@ into @c@ and @1.5@ into @a@, which is truncated to @1@, producing the result @[1, 1]@.
    294292Finally, the tuple @[1, 1]@ is used as an expression in the call to @f@.
    295293
     
    309307In this example, @x@ is initialized by the multiple constructor calls @?{}(&x.0, 3)@ and @?{}(&x.1, 6.28)@, while @y@ is initialized by two default constructor calls @?{}(&y.0)@ and @?{}(&y.1)@.
    310308@z@ is initialized by mass copy constructor calls @?{}(&z.0, x.0)@ and @?{}(&z.1, x.0)@.
    311 Finally, @x@, @y@, and @z@ are destructed, \ie the calls @^?{}(&x.0)@, @^?{}(&x.1)@, @^?{}(&y.0)@, @^?{}(&y.1)@, @^?{}(&z.0)@, and @^?{}(&z.1)@.
     309Finally, @x@, @y@, and @z@ are destructed, i.e. the calls @^?{}(&x.0)@, @^?{}(&x.1)@, @^?{}(&y.0)@, @^?{}(&y.1)@, @^?{}(&z.0)@, and @^?{}(&z.1)@.
    312310
    313311It is possible to define constructors and assignment functions for tuple types that provide new semantics, if the existing semantics do not fit the needs of an application.
     
    342340Then the type of @a.[x, y, z]@ is @[T_x, T_y, T_z]@.
    343341
    344 Since tuple index expressions are a form of member-access expression, it is possible to use tuple-index expressions in conjunction with member tuple expressions to manually restructure a tuple (\eg, rearrange components, drop components, duplicate components, etc.).
     342Since tuple index expressions are a form of member-access expression, it is possible to use tuple-index expressions in conjunction with member tuple expressions to manually restructure a tuple (e.g., rearrange components, drop components, duplicate components, etc.).
    345343\begin{cfacode}
    346344[int, int, long, double] x;
     
    394392
    395393As for @z.y@, one interpretation is to extend the meaning of member tuple expressions.
    396 That is, currently the tuple must occur as the member, \ie to the right of the dot.
     394That is, currently the tuple must occur as the member, i.e. to the right of the dot.
    397395Allowing tuples to the left of the dot could distribute the member across the elements of the tuple, in much the same way that member tuple expressions distribute the aggregate across the member tuple.
    398396In this example, @z.y@ expands to @[z.0.y, z.1.y]@, allowing what is effectively a very limited compile-time field-sections map operation, where the argument must be a tuple containing only aggregates having a member named @y@.
     
    452450
    453451struct A { int x; };
    454 (struct A)f();  // invalid, int cannot be converted to A
     452(struct A)f();  // invalid
    455453\end{cfacode}
    456454In C, line 4 is a valid cast, which calls @f@ and discards its result.
     
    468466  [int, [int, int], int] g();
    469467
    470   ([int, double])f();           // (1) valid
    471   ([int, int, int])g();         // (2) valid
    472   ([void, [int, int]])g();      // (3) valid
    473   ([int, int, int, int])g();    // (4) invalid
    474   ([int, [int, int, int]])g();  // (5) invalid
     468  ([int, double])f();           // (1)
     469  ([int, int, int])g();         // (2)
     470  ([void, [int, int]])g();      // (3)
     471  ([int, int, int, int])g();    // (4)
     472  ([int, [int, int, int]])g();  // (5)
    475473\end{cfacode}
    476474
     
    479477If @g@ is free of side effects, this is equivalent to @[(int)(g().0), (int)(g().1.0), (int)(g().2)]@.
    480478Since @void@ is effectively a 0-element tuple, (3) discards the first and third return values, which is effectively equivalent to @[(int)(g().1.0), (int)(g().1.1)]@).
     479
    481480% will this always hold true? probably, as constructors should give all of the conversion power we need. if casts become function calls, what would they look like? would need a way to specify the target type, which seems awkward. Also, C++ basically only has this because classes are closed to extension, while we don't have that problem (can have floating constructors for any type).
    482481Note that a cast is not a function call in \CFA, so flattening and structuring conversions do not occur for cast expressions.
     
    535534\end{cfacode}
    536535
    537 Until this point, it has been assumed that assertion arguments must match the parameter type exactly, modulo polymorphic specialization (\ie, no implicit conversions are applied to assertion arguments).
     536Until this point, it has been assumed that assertion arguments must match the parameter type exactly, modulo polymorphic specialization (i.e., no implicit conversions are applied to assertion arguments).
    538537This decision presents a conflict with the flexibility of tuples.
    539538\subsection{Assertion Inference}
     
    567566}
    568567\end{cfacode}
    569 is transformed into
     568Is transformed into
    570569\begin{cfacode}
    571570forall(dtype T0, dtype T1 | sized(T0) | sized(T1))
    572 struct _tuple2_ {  // generated before the first 2-tuple
     571struct _tuple2 {  // generated before the first 2-tuple
    573572  T0 field_0;
    574573  T1 field_1;
     
    577576  _tuple2_(double, double) x;
    578577  forall(dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2))
    579   struct _tuple3_ {  // generated before the first 3-tuple
     578  struct _tuple3 {  // generated before the first 3-tuple
    580579    T0 field_0;
    581580    T1 field_1;
     
    590589[5, 'x', 1.24];
    591590\end{cfacode}
    592 becomes
     591Becomes
    593592\begin{cfacode}
    594593(_tuple3_(int, char, double)){ 5, 'x', 1.24 };
     
    604603f(x, 'z');
    605604\end{cfacode}
    606 is transformed into
     605Is transformed into
    607606\begin{cfacode}
    608607void f(int, _tuple2_(double, char));
     
    651650It is possible that lazy evaluation could be exposed to the user through a lazy keyword with little additional effort.
    652651
    653 Tuple-member expressions are recursively expanded into a list of member-access expressions.
     652Tuple member expressions are recursively expanded into a list of member access expressions.
    654653\begin{cfacode}
    655654[int, [double, int, double], int]] x;
    656655x.[0, 1.[0, 2]];
    657656\end{cfacode}
    658 becomes
     657which becomes
    659658\begin{cfacode}
    660659[x.0, [x.1.0, x.1.2]];
     
    671670[x, y, z] = 1.5;            // mass assignment
    672671\end{cfacode}
    673 generates the following
     672Generates the following
    674673\begin{cfacode}
    675674// [x, y, z] = 1.5;
     
    712711});
    713712\end{cfacode}
    714 A variable is generated to store the value produced by a statement expression, since its fields may need to be constructed with a non-trivial constructor and it may need to be referred to multiple time, \eg, in a unique expression.
     713A variable is generated to store the value produced by a statement expression, since its fields may need to be constructed with a non-trivial constructor and it may need to be referred to multiple time, e.g., in a unique expression.
    715714$N$ LHS variables are generated and constructed using the address of the tuple components, and a single RHS variable is generated to store the value of the RHS without any loss of precision.
    716715A nested statement expression is generated that performs the individual assignments and constructs the return value using the results of the individual assignments.
     
    721720[x, y, z] = [f(), 3];       // multiple assignment
    722721\end{cfacode}
    723 generates the following
     722Generates
    724723\begin{cfacode}
    725724// [x, y, z] = [f(), 3];
Note: See TracChangeset for help on using the changeset viewer.