Changes in / [9c32e21:7b28e4a]
- Location:
- doc
- Files:
-
- 3 deleted
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/proposals/user_conversions.md
r9c32e21 r7b28e4a 5 5 There is also a set of _explicit_ conversions that are only allowed through a 6 6 cast expression. 7 I propose that safe, unsafe, and explicit (cast) conversions be expressed as 8 constructor variants. 7 Based on Glen's notes on conversions [1], I propose that safe and unsafe 8 conversions be expressed as constructor variants, though I make explicit 9 (cast) conversions a constructor variant as well rather than a dedicated 10 operator. 9 11 Throughout this article, I will use the following operator names for 10 12 constructors and conversion functions from `From` to `To`: 11 13 12 void ?{} ( To&, To ); // copy constructor 13 void ?{} ( To&, From ); // explicit constructor 14 void ?{explicit} ( To&, From ); // explicit cast conversion 15 void ?{safe} ( To&, From ); // implicit safe conversion 16 void ?{unsafe} ( To&, From ); // implicit unsafe conversion 17 18 It has been suggested that all constructors would define unsafe implicit 14 void ?{} ( To*, To ); // copy constructor 15 void ?{} ( To*, From ); // explicit constructor 16 void ?{explicit} ( To*, From ); // explicit cast conversion 17 void ?{safe} ( To*, From ); // implicit safe conversion 18 void ?{unsafe} ( To*, From ); // implicit unsafe conversion 19 20 [1] http://plg.uwaterloo.ca/~cforall/Conversions/index.html 21 22 Glen's design made no distinction between constructors and unsafe implicit 19 23 conversions; this is elegant, but interacts poorly with tuples. 20 24 Essentially, without making this distinction, a constructor like the following … … 22 26 multiplying the space of possible interpretations of all functions: 23 27 24 void ?{}( Coord &this, int x, int y );28 void ?{}( Coord *this, int x, int y ); 25 29 26 30 That said, it would certainly be possible to make a multiple-argument implicit … … 28 32 used infrequently: 29 33 30 void ?{unsafe}( Coord &this, int x, int y );34 void ?{unsafe}( Coord *this, int x, int y ); 31 35 32 36 An alternate possibility would be to only count two-arg constructors 33 `void ?{} ( To &, From )` as unsafe conversions; under this semantics, safe and37 `void ?{} ( To*, From )` as unsafe conversions; under this semantics, safe and 34 38 explicit conversions should also have a compiler-enforced restriction to 35 39 ensure that they are two-arg functions (this restriction may be valuable … … 39 43 is convertable to `To`. 40 44 If user-defined conversions are not added to the language, 41 `void ?{} ( To &, From )` may be a suitable representation, relying on45 `void ?{} ( To*, From )` may be a suitable representation, relying on 42 46 conversions on the argument types to account for transitivity. 43 Since `To&` should be an exact match on `To`, this should put all the implicit 44 conversions on the RHS. 45 On the other hand, under some models (like [1]), implicit conversions are not 46 allowed in assertion parameters, so another assertion syntax specific to 47 conversions may be required, e.g. `From -> To`. 48 It has also been suggested that, for programmer control, no implicit 49 conversions (except, possibly, for polymorphic specialization) should be 50 allowed in resolution of cast operators. 51 52 [1] ../working/assertion_resolution.md 47 On the other hand, `To*` should perhaps match its target type exactly, so 48 another assertion syntax specific to conversions may be required, e.g. 49 `From -> To`. 53 50 54 51 ### Constructor Idiom ### … … 56 53 that we can use the full range of Cforall features for conversions, including 57 54 polymorphism. 58 In an earlier version of this proposal, Glen Ditchfield defines a 59 _constructor idiom_ that can be used to create chains of safe conversions 60 without duplicating code; given a type `Safe` which members of another type 61 `From` can be directly converted to, the constructor idiom allows us to write 62 a conversion for any type `To` which `Safe` converts to: 63 64 forall(otype To | { void ?{safe}( To&, Safe ) }) 65 void ?{safe}( To& this, From that ) { 55 Glen [1] defines a _constructor idiom_ that can be used to create chains of 56 safe conversions without duplicating code; given a type `Safe` which members 57 of another type `From` can be directly converted to, the constructor idiom 58 allows us to write a conversion for any type `To` which `Safe` converts to: 59 60 forall(otype To | { void ?{safe}( To*, Safe ) }) 61 void ?{safe}( To *this, From that ) { 66 62 Safe tmp = /* some expression involving that */; 67 this{ tmp }; // initialize fromassertion parameter63 *this = tmp; // uses assertion parameter 68 64 } 69 65 … … 71 67 unsafe conversions. 72 68 73 Glen's original suggestion said the copy constructor for `To` should also be74 accepted as a resolution for `void ?{safe}( To&, Safe )` (`Safe` == `To`),75 allowing this same code to be used for the single-step conversion as well.76 This proposal does come at the cost of an extra copy initialization of the77 target value, though.78 79 Contrariwise, if a monomorphic conversion from `From` to `Safe` is written,80 e.g:81 82 void ?{safe}( Safe& this, From that ) {83 this{ /* some parameters involving that */ };84 }85 86 Then the code for a transitive conversion from `From` to any `To` type87 convertable from `Safe` is written:88 89 forall(otype To | { void ?{safe}( To&, Safe ) })90 void ?{safe}( To& this, From that ) {91 Safe tmp = that; // uses monomorphic conversion92 this{ tmp }; // initialize from assertion parameter93 }94 95 Given the entirely-boilerplate nature of this code, but negative performance96 implications of the unmodified constructor idiom, it might be fruitful to have97 transitive and single step conversion operators, and let CFA build the98 transitive conversions; some possible names:99 100 void ?{safe} (To&, From); void ?{final safe} (To&, From); // single-step101 void ?{safe*} (To&, From); void ?{safe} (To&, From); // transitive102 103 69 What selective non-use of the constructor idiom gives us is the ability to 104 70 define a conversion that may only be the *last* conversion in a chain of such. 105 One use for this is to solve the problem that `explicit` conversions were 106 added to C++ for, that of conversions to `bool` chaining to become conversions 107 to any arithmetic type. 108 Another use is to unambiguously represent the full hierarchy of implicit 109 conversions in C by making sign conversions non-transitive, allowing the 110 compiler to resolve e.g. `int -> unsigned long` as 111 `int -> long -> unsigned long` over `int -> unsigned int -> unsigned long`. 112 See [2] for more details. 113 114 [2] ../working/glen_conversions/index.html#usual 71 Constructing a conversion graph able to unambiguously represent the full 72 hierarchy of implicit conversions in C is provably impossible using only 73 single-step conversions with no additional information (see Appendix A), but 74 this mechanism is sufficiently powerful (see [1], though the design there has 75 some minor bugs; the general idea is to use the constructor idiom to define 76 two chains of conversions, one among the signed integral types, another among 77 the unsigned, and to use monomorphic conversions to allow conversions between 78 signed and unsigned integer types). 115 79 116 80 ### Appendix A: Partial and Total Orders ### … … 189 153 convert from `int` to `unsigned long`, so we just put in a direct conversion 190 154 and make the compiler smart enough to figure out the costs" - this is the 191 approach taken by the existing compi ler, but given that in a user-defined155 approach taken by the existing compipler, but given that in a user-defined 192 156 conversion proposal the users can build an arbitrary graph of conversions, 193 157 this case still needs to be handled. … … 196 160 exists a chain of conversions from `a` to `b` (see Appendix A for description 197 161 of preorders and related constructs). 198 This preorder roughly correspondsto a more usual type-theoretic concept of162 This preorder corresponds roughly to a more usual type-theoretic concept of 199 163 subtyping ("if I can convert `a` to `b`, `a` is a more specific type than 200 164 `b`"); however, since this graph is arbitrary, it may contain cycles, so if … … 228 192 and so is considered to be the nearer type. 229 193 By transitivity, then, the conversion from `X` to `Y2` should be cheaper than 230 the conversion from `X` to `W`, but in this case the ` Y2` and `W` are194 the conversion from `X` to `W`, but in this case the `X` and `W` are 231 195 incomparable by the conversion preorder, so the tie is broken by the shorter 232 196 path from `X` to `W` in favour of `W`, contradicting the transitivity property
Note: See TracChangeset
for help on using the changeset viewer.