Changes in / [9c32e21:7b28e4a]


Ignore:
Location:
doc
Files:
3 deleted
1 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/user_conversions.md

    r9c32e21 r7b28e4a  
    55There is also a set of _explicit_ conversions that are only allowed through a
    66cast expression.
    7 I propose that safe, unsafe, and explicit (cast) conversions be expressed as
    8 constructor variants.
     7Based on Glen's notes on conversions [1], I propose that safe and unsafe
     8conversions be expressed as constructor variants, though I make explicit
     9(cast) conversions a constructor variant as well rather than a dedicated
     10operator.
    911Throughout this article, I will use the following operator names for
    1012constructors and conversion functions from `From` to `To`:
    1113
    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
     22Glen's design made no distinction between constructors and unsafe implicit
    1923conversions; this is elegant, but interacts poorly with tuples.
    2024Essentially, without making this distinction, a constructor like the following
     
    2226multiplying the space of possible interpretations of all functions:
    2327
    24         void ?{}( Coord& this, int x, int y );
     28        void ?{}( Coord *this, int x, int y );
    2529
    2630That said, it would certainly be possible to make a multiple-argument implicit
     
    2832used infrequently:
    2933
    30         void ?{unsafe}( Coord& this, int x, int y );
     34        void ?{unsafe}( Coord *this, int x, int y );
    3135
    3236An alternate possibility would be to only count two-arg constructors
    33 `void ?{} ( To&, From )` as unsafe conversions; under this semantics, safe and
     37`void ?{} ( To*, From )` as unsafe conversions; under this semantics, safe and
    3438explicit conversions should also have a compiler-enforced restriction to
    3539ensure that they are two-arg functions (this restriction may be valuable
     
    3943is convertable to `To`.
    4044If user-defined conversions are not added to the language,
    41 `void ?{} ( To&, From )` may be a suitable representation, relying on
     45`void ?{} ( To*, From )` may be a suitable representation, relying on
    4246conversions 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
     47On the other hand, `To*` should perhaps match its target type exactly, so
     48another assertion syntax specific to conversions may be required, e.g.
     49`From -> To`.
    5350
    5451### Constructor Idiom ###
     
    5653that we can use the full range of Cforall features for conversions, including
    5754polymorphism.
    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 ) {
     55Glen [1] defines a _constructor idiom_ that can be used to create chains of
     56safe conversions without duplicating code; given a type `Safe` which members
     57of another type `From` can be directly converted to, the constructor idiom
     58allows 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 ) {
    6662                Safe tmp = /* some expression involving that */;
    67                 this{ tmp }; // initialize from assertion parameter
     63                *this = tmp; // uses assertion parameter
    6864        }
    6965
     
    7167unsafe conversions.
    7268
    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 
    10369What selective non-use of the constructor idiom gives us is the ability to
    10470define 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
     71Constructing a conversion graph able to unambiguously represent the full
     72hierarchy of implicit conversions in C is provably impossible using only
     73single-step conversions with no additional information (see Appendix A), but
     74this mechanism is sufficiently powerful (see [1], though the design there has
     75some minor bugs; the general idea is to use the constructor idiom to define
     76two chains of conversions, one among the signed integral types, another among
     77the unsigned, and to use monomorphic conversions to allow conversions between
     78signed and unsigned integer types).
    11579
    11680### Appendix A: Partial and Total Orders ###
     
    189153convert from `int` to `unsigned long`, so we just put in a direct conversion
    190154and make the compiler smart enough to figure out the costs" - this is the
    191 approach taken by the existing compiler, but given that in a user-defined
     155approach taken by the existing compipler, but given that in a user-defined
    192156conversion proposal the users can build an arbitrary graph of conversions,
    193157this case still needs to be handled.
     
    196160exists a chain of conversions from `a` to `b` (see Appendix A for description
    197161of preorders and related constructs).
    198 This preorder roughly corresponds to a more usual type-theoretic concept of
     162This preorder corresponds roughly to a more usual type-theoretic concept of
    199163subtyping ("if I can convert `a` to `b`, `a` is a more specific type than
    200164`b`"); however, since this graph is arbitrary, it may contain cycles, so if
     
    228192and so is considered to be the nearer type.
    229193By 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` are
     194the conversion from `X` to `W`, but in this case the `X` and `W` are
    231195incomparable by the conversion preorder, so the tie is broken by the shorter
    232196path from `X` to `W` in favour of `W`, contradicting the transitivity property
Note: See TracChangeset for help on using the changeset viewer.