Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/rob_thesis/tuples.tex

    rf92aa32 r0eb18557  
    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 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.
     72Interestingly, 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.
     73In 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.
     74Still, 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.
    7375As with the previous approach, this technique can simulate multiple return values, but in practice it is verbose and error prone.
    7476
     
    8486  char freqs [26] = { 0 };
    8587  int ret_freq = 0;
    86   char ret_ch = 'a';
     88  char ret_ch = 'a';  // arbitrary default value for consistent results
    8789  for (int i = 0; str[i] != '\0'; ++i) {
    8890    if (isalpha(str[i])) {        // only count letters
     
    98100}
    99101\end{cfacode}
    100 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.
     102This 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.
    101103
    102104The addition of multiple-return-value functions necessitates a syntax for accepting multiple values at the call-site.
     
    208210For 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@.
    209211Finally, 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]@.
    210 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.
     212The 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.
    211213
    212214In \KWC \cite{Buhr94a,Till89}, a precursor to \CFA, there were 4 tuple coercions: opening, closing, flattening, and structuring.
    213215Opening coerces a tuple value into a tuple of values, while closing converts a tuple of values into a single tuple value.
    214 Flattening 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.
    215 Structuring moves in the opposite direction, i.e. it takes a flat tuple value and provides structure by introducing nested tuple components.
     216Flattening 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.
     217Structuring moves in the opposite direction, \ie it takes a flat tuple value and provides structure by introducing nested tuple components.
    216218
    217219In \CFA, the design has been simplified to require only the two conversions previously described, which trigger only in function call and return situations.
     
    258260A mass assignment assigns the value $R$ to each $L_i$.
    259261For a mass assignment to be valid, @?=?(&$L_i$, $R$)@ must be a well-typed expression.
    260 These 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.
     262These 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.
    261263For 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@.
    262264On 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.
     
    274276These semantics allow cascading tuple assignment to work out naturally in any context where a tuple is permitted.
    275277These 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.
    276 Restricting 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.
     278Restricting 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.
    277279While 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.
    278280Furthermore, 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.
     
    289291\end{cfacode}
    290292The 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.
    291 That 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]@.
     293That 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]@.
    292294Finally, the tuple @[1, 1]@ is used as an expression in the call to @f@.
    293295
     
    307309In 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)@.
    308310@z@ is initialized by mass copy constructor calls @?{}(&z.0, x.0)@ and @?{}(&z.1, x.0)@.
    309 Finally, @x@, @y@, and @z@ are destructed, i.e. the calls @^?{}(&x.0)@, @^?{}(&x.1)@, @^?{}(&y.0)@, @^?{}(&y.1)@, @^?{}(&z.0)@, and @^?{}(&z.1)@.
     311Finally, @x@, @y@, and @z@ are destructed, \ie the calls @^?{}(&x.0)@, @^?{}(&x.1)@, @^?{}(&y.0)@, @^?{}(&y.1)@, @^?{}(&z.0)@, and @^?{}(&z.1)@.
    310312
    311313It 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.
     
    340342Then the type of @a.[x, y, z]@ is @[T_x, T_y, T_z]@.
    341343
    342 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 (e.g., rearrange components, drop components, duplicate components, etc.).
     344Since 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.).
    343345\begin{cfacode}
    344346[int, int, long, double] x;
     
    392394
    393395As for @z.y@, one interpretation is to extend the meaning of member tuple expressions.
    394 That is, currently the tuple must occur as the member, i.e. to the right of the dot.
     396That is, currently the tuple must occur as the member, \ie to the right of the dot.
    395397Allowing 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.
    396398In 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@.
     
    450452
    451453struct A { int x; };
    452 (struct A)f();  // invalid
     454(struct A)f();  // invalid, int cannot be converted to A
    453455\end{cfacode}
    454456In C, line 4 is a valid cast, which calls @f@ and discards its result.
     
    466468  [int, [int, int], int] g();
    467469
    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)
     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
    473475\end{cfacode}
    474476
     
    477479If @g@ is free of side effects, this is equivalent to @[(int)(g().0), (int)(g().1.0), (int)(g().2)]@.
    478480Since @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 
    480481% 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).
    481482Note that a cast is not a function call in \CFA, so flattening and structuring conversions do not occur for cast expressions.
     
    534535\end{cfacode}
    535536
    536 Until 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).
     537Until 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).
    537538This decision presents a conflict with the flexibility of tuples.
    538539\subsection{Assertion Inference}
     
    566567}
    567568\end{cfacode}
    568 Is transformed into
     569is transformed into
    569570\begin{cfacode}
    570571forall(dtype T0, dtype T1 | sized(T0) | sized(T1))
    571 struct _tuple2 {  // generated before the first 2-tuple
     572struct _tuple2_ {  // generated before the first 2-tuple
    572573  T0 field_0;
    573574  T1 field_1;
     
    576577  _tuple2_(double, double) x;
    577578  forall(dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2))
    578   struct _tuple3 {  // generated before the first 3-tuple
     579  struct _tuple3_ {  // generated before the first 3-tuple
    579580    T0 field_0;
    580581    T1 field_1;
     
    589590[5, 'x', 1.24];
    590591\end{cfacode}
    591 Becomes
     592becomes
    592593\begin{cfacode}
    593594(_tuple3_(int, char, double)){ 5, 'x', 1.24 };
     
    603604f(x, 'z');
    604605\end{cfacode}
    605 Is transformed into
     606is transformed into
    606607\begin{cfacode}
    607608void f(int, _tuple2_(double, char));
     
    650651It is possible that lazy evaluation could be exposed to the user through a lazy keyword with little additional effort.
    651652
    652 Tuple member expressions are recursively expanded into a list of member access expressions.
     653Tuple-member expressions are recursively expanded into a list of member-access expressions.
    653654\begin{cfacode}
    654655[int, [double, int, double], int]] x;
    655656x.[0, 1.[0, 2]];
    656657\end{cfacode}
    657 which becomes
     658becomes
    658659\begin{cfacode}
    659660[x.0, [x.1.0, x.1.2]];
     
    670671[x, y, z] = 1.5;            // mass assignment
    671672\end{cfacode}
    672 Generates the following
     673generates the following
    673674\begin{cfacode}
    674675// [x, y, z] = 1.5;
     
    711712});
    712713\end{cfacode}
    713 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, e.g., in a unique expression.
     714A 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.
    714715$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.
    715716A nested statement expression is generated that performs the individual assignments and constructs the return value using the results of the individual assignments.
     
    720721[x, y, z] = [f(), 3];       // multiple assignment
    721722\end{cfacode}
    722 Generates
     723generates the following
    723724\begin{cfacode}
    724725// [x, y, z] = [f(), 3];
Note: See TracChangeset for help on using the changeset viewer.