Changes in doc/rob_thesis/tuples.tex [f92aa32:0eb18557]
- File:
-
- 1 edited
-
doc/rob_thesis/tuples.tex (modified) (22 diffs)
Legend:
- Unmodified
- Added
- Removed
-
doc/rob_thesis/tuples.tex
rf92aa32 r0eb18557 70 70 Furthermore, 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. 71 71 On 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. 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. 73 75 As with the previous approach, this technique can simulate multiple return values, but in practice it is verbose and error prone. 74 76 … … 84 86 char freqs [26] = { 0 }; 85 87 int ret_freq = 0; 86 char ret_ch = 'a'; 88 char ret_ch = 'a'; // arbitrary default value for consistent results 87 89 for (int i = 0; str[i] != '\0'; ++i) { 88 90 if (isalpha(str[i])) { // only count letters … … 98 100 } 99 101 \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.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. 101 103 102 104 The addition of multiple-return-value functions necessitates a syntax for accepting multiple values at the call-site. … … 208 210 For 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@. 209 211 Finally, 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.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. 211 213 212 214 In \KWC \cite{Buhr94a,Till89}, a precursor to \CFA, there were 4 tuple coercions: opening, closing, flattening, and structuring. 213 215 Opening 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.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. 216 218 217 219 In \CFA, the design has been simplified to require only the two conversions previously described, which trigger only in function call and return situations. … … 258 260 A mass assignment assigns the value $R$ to each $L_i$. 259 261 For 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.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. 261 263 For 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@. 262 264 On 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. … … 274 276 These semantics allow cascading tuple assignment to work out naturally in any context where a tuple is permitted. 275 277 These 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.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. 277 279 While 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. 278 280 Furthermore, 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. … … 289 291 \end{cfacode} 290 292 The 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]@.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]@. 292 294 Finally, the tuple @[1, 1]@ is used as an expression in the call to @f@. 293 295 … … 307 309 In 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)@. 308 310 @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)@.311 Finally, @x@, @y@, and @z@ are destructed, \ie the calls @^?{}(&x.0)@, @^?{}(&x.1)@, @^?{}(&y.0)@, @^?{}(&y.1)@, @^?{}(&z.0)@, and @^?{}(&z.1)@. 310 312 311 313 It 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. … … 340 342 Then the type of @a.[x, y, z]@ is @[T_x, T_y, T_z]@. 341 343 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.).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.). 343 345 \begin{cfacode} 344 346 [int, int, long, double] x; … … 392 394 393 395 As 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.396 That is, currently the tuple must occur as the member, \ie to the right of the dot. 395 397 Allowing 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. 396 398 In 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@. … … 450 452 451 453 struct A { int x; }; 452 (struct A)f(); // invalid 454 (struct A)f(); // invalid, int cannot be converted to A 453 455 \end{cfacode} 454 456 In C, line 4 is a valid cast, which calls @f@ and discards its result. … … 466 468 [int, [int, int], int] g(); 467 469 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 473 475 \end{cfacode} 474 476 … … 477 479 If @g@ is free of side effects, this is equivalent to @[(int)(g().0), (int)(g().1.0), (int)(g().2)]@. 478 480 Since @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 480 481 % 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). 481 482 Note that a cast is not a function call in \CFA, so flattening and structuring conversions do not occur for cast expressions. … … 534 535 \end{cfacode} 535 536 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).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). 537 538 This decision presents a conflict with the flexibility of tuples. 538 539 \subsection{Assertion Inference} … … 566 567 } 567 568 \end{cfacode} 568 Is transformed into569 is transformed into 569 570 \begin{cfacode} 570 571 forall(dtype T0, dtype T1 | sized(T0) | sized(T1)) 571 struct _tuple2 { // generated before the first 2-tuple572 struct _tuple2_ { // generated before the first 2-tuple 572 573 T0 field_0; 573 574 T1 field_1; … … 576 577 _tuple2_(double, double) x; 577 578 forall(dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2)) 578 struct _tuple3 { // generated before the first 3-tuple579 struct _tuple3_ { // generated before the first 3-tuple 579 580 T0 field_0; 580 581 T1 field_1; … … 589 590 [5, 'x', 1.24]; 590 591 \end{cfacode} 591 Becomes592 becomes 592 593 \begin{cfacode} 593 594 (_tuple3_(int, char, double)){ 5, 'x', 1.24 }; … … 603 604 f(x, 'z'); 604 605 \end{cfacode} 605 Is transformed into606 is transformed into 606 607 \begin{cfacode} 607 608 void f(int, _tuple2_(double, char)); … … 650 651 It is possible that lazy evaluation could be exposed to the user through a lazy keyword with little additional effort. 651 652 652 Tuple member expressions are recursively expanded into a list of memberaccess expressions.653 Tuple-member expressions are recursively expanded into a list of member-access expressions. 653 654 \begin{cfacode} 654 655 [int, [double, int, double], int]] x; 655 656 x.[0, 1.[0, 2]]; 656 657 \end{cfacode} 657 whichbecomes658 becomes 658 659 \begin{cfacode} 659 660 [x.0, [x.1.0, x.1.2]]; … … 670 671 [x, y, z] = 1.5; // mass assignment 671 672 \end{cfacode} 672 Generates the following673 generates the following 673 674 \begin{cfacode} 674 675 // [x, y, z] = 1.5; … … 711 712 }); 712 713 \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.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. 714 715 $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. 715 716 A nested statement expression is generated that performs the individual assignments and constructs the return value using the results of the individual assignments. … … 720 721 [x, y, z] = [f(), 3]; // multiple assignment 721 722 \end{cfacode} 722 Generates 723 generates the following 723 724 \begin{cfacode} 724 725 // [x, y, z] = [f(), 3];
Note:
See TracChangeset
for help on using the changeset viewer.