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