| [fc568163] | 1 | Operator Defaults | 
|---|
|  | 2 | ================= | 
|---|
|  | 3 |  | 
|---|
|  | 4 | This proposal introduces a new syntax for requesting a default implementation | 
|---|
|  | 5 | of an operator and the rules for generating them. | 
|---|
|  | 6 |  | 
|---|
|  | 7 | This is to build on the implied relationships between operators. Most default | 
|---|
|  | 8 | operators will be implemented in terms of other operators. As a fall-back | 
|---|
|  | 9 | operators can try to figure out an intuitive definition from inspection of the | 
|---|
|  | 10 | type's sue declaration. | 
|---|
|  | 11 |  | 
|---|
|  | 12 | Syntax | 
|---|
|  | 13 | ------ | 
|---|
|  | 14 |  | 
|---|
|  | 15 | The syntax for requesting a default implementation is part of function | 
|---|
|  | 16 | definition. After the function signature (after the parameter list) instead | 
|---|
|  | 17 | of putting the function body you declare it to be equal to default. | 
|---|
|  | 18 |  | 
|---|
|  | 19 | box ?+?(box const & left, box const & right) = default; | 
|---|
|  | 20 |  | 
|---|
|  | 21 | These can exist along side any forward definitions of the function, but would | 
|---|
|  | 22 | conflict with any other complete definitions or deletions of the function. | 
|---|
|  | 23 |  | 
|---|
|  | 24 | It could be valid syntax on any function, but possibly all non-operators would | 
|---|
|  | 25 | report that no default implementation available. | 
|---|
|  | 26 |  | 
|---|
|  | 27 | If default implementations are really popular and we don't need additional | 
|---|
|  | 28 | information about the signature a more compact syntax could be added. | 
|---|
|  | 29 |  | 
|---|
|  | 30 | default box( ?(), ?=?, ?!=?, ?<?, ?>?, ?<=?, ?>=? ); | 
|---|
|  | 31 |  | 
|---|
|  | 32 | Generation Strategies | 
|---|
|  | 33 | --------------------- | 
|---|
|  | 34 |  | 
|---|
|  | 35 | There exists a system around the default generation that selects how to | 
|---|
|  | 36 | generate a given function if one can be generated at all. This section | 
|---|
|  | 37 | describes that system and some of the logic behind it. | 
|---|
|  | 38 |  | 
|---|
|  | 39 | There are two main strategies for generating an operator implementation. | 
|---|
|  | 40 |  | 
|---|
|  | 41 | The first is to mimic the relationship between operators on the primitive | 
|---|
|  | 42 | types by defining a new operator in terms of an existing operator on the same | 
|---|
|  | 43 | type. For instance `++i` is equivalent to `i += 1`, so the generated | 
|---|
|  | 44 | implementation will "look like" that. | 
|---|
|  | 45 |  | 
|---|
|  | 46 | The second is to inspect the structure of the declaration to guess at what | 
|---|
|  | 47 | the default implementation would be. Because of that it is dependent on the | 
|---|
|  | 48 | kind of declaration, a structure doesn't have the same rules as an | 
|---|
|  | 49 | enumeration. Also it is similar to the implicate definitions currently created | 
|---|
|  | 50 | by the compiler and the generation methods for many are carried over. | 
|---|
|  | 51 |  | 
|---|
|  | 52 | From these strategies a method of generation (a particular set of rules that | 
|---|
|  | 53 | define an implementation from the type and existing functions) has to be | 
|---|
|  | 54 | picked, but often there is more than on reasonable choice. In these cases they | 
|---|
|  | 55 | are ordered and the first (best) one whose requirements is met is then used. | 
|---|
|  | 56 | See "Circular Requirements" below for some exceptions and extensions to this | 
|---|
|  | 57 | pattern. | 
|---|
|  | 58 |  | 
|---|
|  | 59 | Generally the methods based on operators come first as they propagate any | 
|---|
|  | 60 | unusual implementations from the explicate operators to the ones being | 
|---|
|  | 61 | generated. If all of those fail then the intuitive definition based on the | 
|---|
|  | 62 | declaration's shape is used. The general patterns in this area for the | 
|---|
|  | 63 | different sue types follow. | 
|---|
|  | 64 |  | 
|---|
|  | 65 | ### Structures | 
|---|
|  | 66 | Structures will usually apply the operation to each field, or when there are | 
|---|
|  | 67 | two parameters the matching pairs of fields from each, and then combine the | 
|---|
|  | 68 | results. | 
|---|
|  | 69 |  | 
|---|
|  | 70 | This does require that the fields have certain operators defined on them. | 
|---|
|  | 71 | In this respect it is still operator based generation, but we use inspection | 
|---|
|  | 72 | on the structure to find out which operators to use. | 
|---|
|  | 73 |  | 
|---|
|  | 74 | Also, for the purposes of default generation types declared with the | 
|---|
|  | 75 | concurrency modifiers (coroutine, monitor and thread) are considered structs. | 
|---|
|  | 76 | The default implementations should be the same as if you had written out the | 
|---|
|  | 77 | extra field and functions by hand. | 
|---|
|  | 78 |  | 
|---|
|  | 79 | ### Enumerations | 
|---|
|  | 80 | The two ways of using enumerations are considered. First as "one of" the | 
|---|
|  | 81 | list options as in normal use, the second is as a set of flags where each | 
|---|
|  | 82 | option represents a flag that may or may not be set. | 
|---|
|  | 83 |  | 
|---|
|  | 84 | Currently there is no way to specify which nor does the system attempt to | 
|---|
|  | 85 | guess by checking assigned values. There is one case where an operator could | 
|---|
|  | 86 | have a meaningful default in both versions. If both are included then we can | 
|---|
|  | 87 | try to pick one by scanning the enumeration to see what values its options | 
|---|
|  | 88 | are given (a linear series or powers of 2) could be used. In all other cases | 
|---|
|  | 89 | the definition that makes sense can be assumed. | 
|---|
|  | 90 |  | 
|---|
|  | 91 | ### Unions | 
|---|
|  | 92 | Unions are the hardest to deal with because the instance does not show which | 
|---|
|  | 93 | field in the union is being used. Because of that there are very few intuitive | 
|---|
|  | 94 | definitions to use and the ones that do depend on bit-wise operations and only | 
|---|
|  | 95 | if the union is made of primitive types. | 
|---|
|  | 96 |  | 
|---|
|  | 97 | ### Traits | 
|---|
|  | 98 | Default operations are not supported on traits. A function implemented by the | 
|---|
|  | 99 | default generation may be used to satisfy an assertion. However a default | 
|---|
|  | 100 | implementation may not be requested on a polymorphic function. | 
|---|
|  | 101 |  | 
|---|
|  | 102 | It could in theory, limiting to operation based generation and using the | 
|---|
|  | 103 | operations available in the assertion list. There are a few problems: | 
|---|
|  | 104 | +   Knowing the entire set of functions being generated is very useful in some | 
|---|
|  | 105 | cases and this information is quickly lost with polymorphic functions. | 
|---|
|  | 106 | +   The rules for choosing a generation method do not match how a polymorphic | 
|---|
|  | 107 | function is selected so the results can be inconsistent. | 
|---|
|  | 108 | +   It is easily to mimic with a polymorphic function already, writing out one | 
|---|
|  | 109 | generic function and including it. | 
|---|
|  | 110 |  | 
|---|
|  | 111 | Default Generation | 
|---|
|  | 112 | ------------------ | 
|---|
|  | 113 |  | 
|---|
|  | 114 | Here are the generation methods. Unless otherwise stated they are listed in | 
|---|
|  | 115 | priority order. That is the first one mentioned that a type fits (has all the | 
|---|
|  | 116 | required operators or its form matches) will be used. | 
|---|
|  | 117 |  | 
|---|
|  | 118 | The operator based constructions can be used on any sue type, those that | 
|---|
|  | 119 | require a particular kind mention that. | 
|---|
|  | 120 |  | 
|---|
|  | 121 | ### Constructor: ?{} | 
|---|
|  | 122 | Note that requesting any constructor to be generated counts as defining a | 
|---|
|  | 123 | constructor for purposes of disabling the implicate constructors. There are | 
|---|
|  | 124 | no operator based methods for generating constructors. | 
|---|
|  | 125 |  | 
|---|
|  | 126 | For structures: For the zero argument constructor (aka the default constructor, | 
|---|
|  | 127 | which takes just a reference to the value to construct) each field is | 
|---|
|  | 128 | constructed with its zero argument constructor. For the copy constructor each | 
|---|
|  | 129 | field is copy constructed from the same field in the copied structure. For | 
|---|
|  | 130 | zero_t and one_t each field is also constructed from zero_t or one_t. | 
|---|
|  | 131 |  | 
|---|
|  | 132 | For enumerations: For the zero argument constructor the value is set to 0 if | 
|---|
|  | 133 | one of the enumeration options is 0 (or set to the first value in the enum). | 
|---|
|  | 134 | For the zero_t constructor it is the same except the check is skipped (and no | 
|---|
|  | 135 | or). The copy constructor is the same as memcpy. | 
|---|
|  | 136 |  | 
|---|
|  | 137 | For unions: For the zero argument constructor of a union that is constructed | 
|---|
|  | 138 | entirely of primitive types (or other types that zero argument construct to | 
|---|
|  | 139 | all 0s) the union filled with 0s. For the copy constructor of a union of types | 
|---|
|  | 140 | that all have trivial copy constructors memcpy is used. | 
|---|
|  | 141 |  | 
|---|
|  | 142 | ### Destructor: ^?{} | 
|---|
|  | 143 | Requesting the default destructor should be the same as having it implicitly | 
|---|
|  | 144 | defined. Destructors only have one signature and the intuitive definition for | 
|---|
|  | 145 | that is the same as without the signature. | 
|---|
|  | 146 |  | 
|---|
|  | 147 | Still it should be allowed for consistency. It also allows it to be forward | 
|---|
|  | 148 | declared and then generated in a .cfa file. | 
|---|
|  | 149 |  | 
|---|
|  | 150 | ### Assignment: ?=? | 
|---|
|  | 151 | Default assignment is only supported between two objects of the same type. | 
|---|
|  | 152 | For structures it is field to field assignment. For enumerations and unions | 
|---|
|  | 153 | of primitives or trivially copiable types it the same as memcpy. | 
|---|
|  | 154 |  | 
|---|
|  | 155 | ### Equality: ?==? ?!=? | 
|---|
|  | 156 | Both equality operations can be implemented by negating the result of the | 
|---|
|  | 157 | other operations. | 
|---|
|  | 158 |  | 
|---|
|  | 159 | For structures: Equality can be implement by checking equality on each pair of | 
|---|
|  | 160 | matching fields and taking the logical and of the results. Inequality can be | 
|---|
|  | 161 | implemented by checking inequality on each pair of matching fields and taking | 
|---|
|  | 162 | the logical or of the results. | 
|---|
|  | 163 |  | 
|---|
|  | 164 | Both logical operations could be short circuiting. Without side effects it is | 
|---|
|  | 165 | purely an optimization. | 
|---|
|  | 166 |  | 
|---|
|  | 167 | For enumerations: Both operations are the same as on the underlying integral. | 
|---|
|  | 168 |  | 
|---|
|  | 169 | For unions: If it is assumed that the different branches represent different | 
|---|
|  | 170 | views of the same data and this data is primitive, than bit-wise comparisons | 
|---|
|  | 171 | can be used. | 
|---|
|  | 172 |  | 
|---|
|  | 173 | ### Comparison: ?<? ?>? ?<=? ?>=? | 
|---|
|  | 174 | Less than can be implemented by flipping the arguments on greater than. | 
|---|
|  | 175 | Greater than can be implemented by flipping less then. Less than or equal to | 
|---|
|  | 176 | can be implemented by flipping greater than or equal to. Greater than or equal | 
|---|
|  | 177 | to can be implemented by flipping less than or equal to. | 
|---|
|  | 178 |  | 
|---|
|  | 179 | Less than or equal to can be implemented by using less than, equals and taking | 
|---|
|  | 180 | the or of the results. Greater than or equal to can be implemented by using | 
|---|
|  | 181 | greater than, equals and taking the or of the results. | 
|---|
|  | 182 |  | 
|---|
|  | 183 | > The trick of negating comparisons is not used. As an example ?<? is not | 
|---|
|  | 184 | > (boolean) not ?>=? unless the type is strictly ordered. For operator based | 
|---|
|  | 185 | > overloads that might not be true in very reasonable implementations so it is | 
|---|
|  | 186 | > not assumed. | 
|---|
|  | 187 |  | 
|---|
|  | 188 | Opposite less than can be implemented as less than or equal to and not equal | 
|---|
|  | 189 | to. Greater than can be implemented as greater than or equal to and not equal | 
|---|
|  | 190 | to. | 
|---|
|  | 191 |  | 
|---|
|  | 192 | For enumerations: Enumerations that represent one of all operations are the | 
|---|
|  | 193 | same as on the underlying integral. Enumerations that represent a set of | 
|---|
|  | 194 | options could replace less then with subset of and greator than with superset | 
|---|
|  | 195 | of and use bit-wise masking to implement those operations. | 
|---|
|  | 196 |  | 
|---|
|  | 197 | ### Binary & Relative Assignment Operators: ?_? ?_=? | 
|---|
|  | 198 | This applies to each operator in the form of `T ?_?(T, T);` for some type T | 
|---|
|  | 199 | and has a matching relative assignment operator `T& ?_=?(T&, T)` where the | 
|---|
|  | 200 | `_` in both is replaced by some string of operator characters. | 
|---|
|  | 201 |  | 
|---|
|  | 202 | The binary operator can be created by copying the left argument, using the | 
|---|
|  | 203 | relative assignment with the right argument and returning the updated copy. | 
|---|
|  | 204 |  | 
|---|
|  | 205 | The relative assignment operator can be implemented by using the binary | 
|---|
|  | 206 | operation to create a copy, then assigning the result to the left argument. | 
|---|
|  | 207 | The left argument should then be returned. For the signature above it would | 
|---|
|  | 208 | return by reference. The signature `T ?_=?(T&, T)` could also be supported in | 
|---|
|  | 209 | which case it would return by copy. | 
|---|
|  | 210 |  | 
|---|
|  | 211 | ### Minus: -? ?-? | 
|---|
|  | 212 | Unary minus can be implemented by subtracting argument from the value created | 
|---|
|  | 213 | from zero_t. | 
|---|
|  | 214 |  | 
|---|
|  | 215 | Binary minus can be implemented by negating (with unary minus) the right | 
|---|
|  | 216 | argument and adding the result to the left argument. | 
|---|
|  | 217 |  | 
|---|
|  | 218 | ### Increment & Decrement: ++? ?++ --? ?-- | 
|---|
|  | 219 | Either pre- operation can implemented by applying the post- operation and then | 
|---|
|  | 220 | returning a reference to, or copy of, the updated value. Either post- | 
|---|
|  | 221 | operation can be implemented by copying the argument, applying the pre- | 
|---|
|  | 222 | operation to the original and returning the copy. | 
|---|
|  | 223 |  | 
|---|
|  | 224 | Pre-increment can be implemented by using addition assignment by the value | 
|---|
|  | 225 | constructed from one_t. Pre-decrement can be implemented by using subtraction | 
|---|
|  | 226 | assignment by the value from one_t. | 
|---|
|  | 227 |  | 
|---|
|  | 228 | Because many of the operations used have there own default implementations | 
|---|
|  | 229 | (for example: ?+=? from ?+? or field-wise one_t construction) this list could | 
|---|
|  | 230 | be expanded by replacing a function call with the default implementation for | 
|---|
|  | 231 | that function. This might work for the post- operations generated from | 
|---|
|  | 232 | relative assignment, the one_t constructed object and copying, but the logical | 
|---|
|  | 233 | connection becomes weaker and weaker as that process continues. | 
|---|
|  | 234 |  | 
|---|
|  | 235 | ### Bit Manipulation: ?|? ?&? ~? ?<<? ?>>? | 
|---|
|  | 236 | No operation based construction is provided for bit manipulation operators. | 
|---|
|  | 237 |  | 
|---|
|  | 238 | For enumerations that are considered sets of flags: And returns a set with all | 
|---|
|  | 239 | flags set in both operand sets, or returns a set with all flags set that are | 
|---|
|  | 240 | set in either operand sets and not returns a set with all flags set that are | 
|---|
|  | 241 | not set in the operand set. | 
|---|
|  | 242 |  | 
|---|
|  | 243 | > And it would be possible to actually implement this for any sized type and | 
|---|
|  | 244 | > just do the bitwise operation and trust the user that it makes sense if they | 
|---|
|  | 245 | > request it. | 
|---|
|  | 246 |  | 
|---|
|  | 247 | Also for set enumerations, the signature `T ?<<?(one_t, unsigned)` also has | 
|---|
|  | 248 | some use, as it can be used to implement a loop that goes over each flag, | 
|---|
|  | 249 | instead of each combination of flags. | 
|---|
|  | 250 |  | 
|---|
|  | 251 | ### Logical Negation: !? | 
|---|
|  | 252 | Not can be implemented by negating the result of a conversion to boolean, the | 
|---|
|  | 253 | does not equal 0 test. | 
|---|
|  | 254 |  | 
|---|
|  | 255 | Circular Requirements | 
|---|
|  | 256 | --------------------- | 
|---|
|  | 257 |  | 
|---|
|  | 258 | There are several cases where there are two operators that can be implemented | 
|---|
|  | 259 | with the other operator. If both are implemented that way calling either of | 
|---|
|  | 260 | them could result in infinite recursion. | 
|---|
|  | 261 |  | 
|---|
|  | 262 | The simplest way to handle the issue would be to tell the user to not do that, | 
|---|
|  | 263 | they are responsible for providing the base operations. This is C like but is | 
|---|
|  | 264 | perhaps more error prone than it would save in work and if we do check we can | 
|---|
|  | 265 | automatically use fallbacks. | 
|---|
|  | 266 |  | 
|---|
|  | 267 | Before generating any default implementations the compiler should generate | 
|---|
|  | 268 | a list of everything it has been requested and ignore any generation methods | 
|---|
|  | 269 | that would lead to chains instead of counting other defaults that could lead | 
|---|
|  | 270 | to a loop. As a further improvment this could be done selectively to break | 
|---|
|  | 271 | rings while allowing chains of non-recurive implementations. | 
|---|
|  | 272 |  | 
|---|
|  | 273 | For instance if both ?==? and ?!=? are requested they cannot both be defined | 
|---|
|  | 274 | as the negation of each other. In the simple version they would both be | 
|---|
|  | 275 | generated by introspection on the declaration. With the more selective version | 
|---|
|  | 276 | one could be generated by introspection and the other by negating that result. | 
|---|
|  | 277 |  | 
|---|
|  | 278 | However there are still ways to get around this by placing the function | 
|---|
|  | 279 | definitions in different translation units or defining a function that uses | 
|---|
|  | 280 | an operator that is default generated to use it. Searching for all these cases | 
|---|
|  | 281 | is probably not worth it, although checking for some might be useful warnings. | 
|---|