Changeset f184ca3
- Timestamp:
- Jun 9, 2018, 8:21:14 PM (6 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, with_gc
- Children:
- 3fc59bdb, 61accc5, e04aec4
- Parents:
- 332d3c2 (diff), 9c32e21 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- doc
- Files:
-
- 3 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/proposals/user_conversions.md
r332d3c2 rf184ca3 5 5 There is also a set of _explicit_ conversions that are only allowed through a 6 6 cast expression. 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. 7 I propose that safe, unsafe, and explicit (cast) conversions be expressed as 8 constructor variants. 11 9 Throughout this article, I will use the following operator names for 12 10 constructors and conversion functions from `From` to `To`: 13 11 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 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 23 19 conversions; this is elegant, but interacts poorly with tuples. 24 20 Essentially, without making this distinction, a constructor like the following … … 26 22 multiplying the space of possible interpretations of all functions: 27 23 28 void ?{}( Coord *this, int x, int y );24 void ?{}( Coord& this, int x, int y ); 29 25 30 26 That said, it would certainly be possible to make a multiple-argument implicit … … 32 28 used infrequently: 33 29 34 void ?{unsafe}( Coord *this, int x, int y );30 void ?{unsafe}( Coord& this, int x, int y ); 35 31 36 32 An alternate possibility would be to only count two-arg constructors 37 `void ?{} ( To *, From )` as unsafe conversions; under this semantics, safe and33 `void ?{} ( To&, From )` as unsafe conversions; under this semantics, safe and 38 34 explicit conversions should also have a compiler-enforced restriction to 39 35 ensure that they are two-arg functions (this restriction may be valuable … … 43 39 is convertable to `To`. 44 40 If user-defined conversions are not added to the language, 45 `void ?{} ( To *, From )` may be a suitable representation, relying on41 `void ?{} ( To&, From )` may be a suitable representation, relying on 46 42 conversions on the argument types to account for transitivity. 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`. 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 50 53 51 54 ### Constructor Idiom ### … … 53 56 that we can use the full range of Cforall features for conversions, including 54 57 polymorphism. 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 ) { 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 ) { 62 66 Safe tmp = /* some expression involving that */; 63 *this = tmp; // usesassertion parameter67 this{ tmp }; // initialize from assertion parameter 64 68 } 65 69 … … 67 71 unsafe conversions. 68 72 73 Glen's original suggestion said the copy constructor for `To` should also be 74 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 the 77 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` type 87 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 conversion 92 this{ tmp }; // initialize from assertion parameter 93 } 94 95 Given the entirely-boilerplate nature of this code, but negative performance 96 implications of the unmodified constructor idiom, it might be fruitful to have 97 transitive and single step conversion operators, and let CFA build the 98 transitive conversions; some possible names: 99 100 void ?{safe} (To&, From); void ?{final safe} (To&, From); // single-step 101 void ?{safe*} (To&, From); void ?{safe} (To&, From); // transitive 102 69 103 What selective non-use of the constructor idiom gives us is the ability to 70 104 define a conversion that may only be the *last* conversion in a chain of such. 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). 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 79 115 80 116 ### Appendix A: Partial and Total Orders ### … … 153 189 convert from `int` to `unsigned long`, so we just put in a direct conversion 154 190 and make the compiler smart enough to figure out the costs" - this is the 155 approach taken by the existing compi pler, but given that in a user-defined191 approach taken by the existing compiler, but given that in a user-defined 156 192 conversion proposal the users can build an arbitrary graph of conversions, 157 193 this case still needs to be handled. … … 160 196 exists a chain of conversions from `a` to `b` (see Appendix A for description 161 197 of preorders and related constructs). 162 This preorder corresponds roughlyto a more usual type-theoretic concept of198 This preorder roughly corresponds to a more usual type-theoretic concept of 163 199 subtyping ("if I can convert `a` to `b`, `a` is a more specific type than 164 200 `b`"); however, since this graph is arbitrary, it may contain cycles, so if … … 192 228 and so is considered to be the nearer type. 193 229 By transitivity, then, the conversion from `X` to `Y2` should be cheaper than 194 the conversion from `X` to `W`, but in this case the ` X` and `W` are230 the conversion from `X` to `W`, but in this case the `Y2` and `W` are 195 231 incomparable by the conversion preorder, so the tie is broken by the shorter 196 232 path from `X` to `W` in favour of `W`, contradicting the transitivity property
Note: See TracChangeset
for help on using the changeset viewer.