@@ -110,27 +110,36 @@ might expect: we introduce a total of *four* traits:
110
110
111
111
``` rust
112
112
trait As <Sized ? T > for Sized ? {
113
- fn cvt_as (& self ) -> & T ;
113
+ fn convert_as (& self ) -> & T ;
114
114
}
115
115
116
116
trait AsMut <Sized ? T > for Sized ? {
117
- fn cvt_as_mut (& mut self ) -> & mut T ;
117
+ fn convert_as_mut (& mut self ) -> & mut T ;
118
118
}
119
119
120
120
trait To <T > for Sized ? {
121
- fn cvt_to (& self ) -> T ;
121
+ fn convert_to (& self ) -> T ;
122
122
}
123
123
124
124
trait Into <T > {
125
- fn cvt_into (self ) -> T ;
125
+ fn convert_into (self ) -> T ;
126
+ }
127
+
128
+ trait From <T > {
129
+ fn from (T ) -> Self ;
126
130
}
127
131
```
128
132
129
- These traits mirror our ` as ` /` to ` /` into ` conventions, but add a bit
130
- more structure to them: ` as ` -style conversions are from references to
131
- references, ` to ` -style conversions are from references to arbitrary
132
- types, and ` into ` -style conversions are between arbitrary types
133
- (consuming their argument).
133
+ The first three traits mirror our ` as ` /` to ` /` into ` conventions, but
134
+ add a bit more structure to them: ` as ` -style conversions are from
135
+ references to references, ` to ` -style conversions are from references
136
+ to arbitrary types, and ` into ` -style conversions are between arbitrary
137
+ types (consuming their argument).
138
+
139
+ The final trait, ` From ` , mimics the ` from ` constructors. Unlike the
140
+ other traits, its method is not prefixed with ` convert ` . This is
141
+ because, again unlike the other traits, this trait is expected to
142
+ outright replace most custom ` from ` constructors. See below.
134
143
135
144
** Why the reference restrictions?**
136
145
@@ -140,7 +149,7 @@ would have to use generalized where clauses and explicit lifetimes even for simp
140
149
``` rust
141
150
// Possible alternative:
142
151
trait As <T > {
143
- fn cvt_as (self ) -> T ;
152
+ fn convert_as (self ) -> T ;
144
153
}
145
154
146
155
// But then you get this:
@@ -150,17 +159,19 @@ fn take_as<'a, T>(t: &'a T) where &'a T: As<&'a MyType>;
150
159
fn take_as <T >(t : & T ) where T : As <MyType >;
151
160
```
152
161
153
- What's worse, if you need a conversion that works over any lifetime,
154
- * there's no way to specify it * : you can't write something like
162
+ If you need a conversion that works over any lifetime, you need to use
163
+ higher-ranked trait bounds:
155
164
156
165
``` rust
157
166
... where for <'a > & 'a T : As <& 'a MyType >
158
167
```
159
168
160
169
This case is particularly important when you cannot name a lifetime in
161
170
advance, because it will be created on the stack within the
162
- function. While such a ` where ` clause can likely be added in the
163
- future, it's a bit of a gamble to pin conversion traits on it today.
171
+ function. It might be possible to add sugar so that `where &T:
172
+ As<&MyType>` expands to the above automatically, but such an elision
173
+ might have other problems, and in any case it would preclude writing
174
+ direct bounds like ` fn foo<P: AsPath> ` .
164
175
165
176
The proposed trait definition essentially * bakes in* the needed
166
177
lifetime connection, capturing the most common mode of use for
@@ -176,6 +187,14 @@ cost and consumption, and having multiple traits makes it possible to
176
187
(by convention) restrict attention to e.g. "free" ` as ` -style conversions
177
188
by bounding only by ` As ` .
178
189
190
+ Why have both ` Into ` and ` From ` ? There are a few reasons:
191
+
192
+ * Coherence issues: the order of the types is significant, so ` From `
193
+ allows extensibility in some cases that ` Into ` does not.
194
+
195
+ * To match with existing conventions around conversions and
196
+ constructors (in particular, replacing many ` from ` constructors).
197
+
179
198
## Blanket ` impl ` s
180
199
181
200
Given the above trait design, there are a few straightforward blanket
@@ -184,53 +203,60 @@ Given the above trait design, there are a few straightforward blanket
184
203
``` rust
185
204
// As implies To
186
205
impl <'a , Sized ? T , Sized ? U > To <& 'a U > for & 'a T where T : As <U > {
187
- fn cvt_to (& self ) -> & 'a U {
188
- self . cvt_as ()
206
+ fn convert_to (& self ) -> & 'a U {
207
+ self . convert_as ()
189
208
}
190
209
}
191
210
192
211
// To implies Into
193
212
impl <'a , T , U > Into <U > for & 'a T where T : To <U > {
194
- fn cvt_into (self ) -> U {
195
- self . cvt_to ()
213
+ fn convert_into (self ) -> U {
214
+ self . convert_to ()
196
215
}
197
216
}
198
217
199
218
// AsMut implies Into
200
219
impl <'a , T , U > Into <& 'a mut U > for & 'a mut T where T : AsMut <U > {
201
- fn cvt_into (self ) -> & 'a mut U {
202
- self . cvt_as_mut ()
220
+ fn convert_into (self ) -> & 'a mut U {
221
+ self . convert_as_mut ()
203
222
}
204
223
}
224
+
225
+ // Into implies From
226
+ impl <T , U > From <T > for U where T : Into <U > {
227
+ fn from (t : T ) -> U { t . cvt_into () }
228
+ }
205
229
```
206
230
231
+ The interaction between
232
+
207
233
## An example
208
234
209
235
Using all of the above, here are some example ` impl ` s and their use:
210
236
211
237
``` rust
212
238
impl As <str > for String {
213
- fn cvt_as (& self ) -> & str {
239
+ fn convert_as (& self ) -> & str {
214
240
self . as_slice ()
215
241
}
216
242
}
217
243
impl As <[u8 ]> for String {
218
- fn cvt_as (& self ) -> & [u8 ] {
244
+ fn convert_as (& self ) -> & [u8 ] {
219
245
self . as_bytes ()
220
246
}
221
247
}
222
248
223
249
impl Into <Vec <u8 >> for String {
224
- fn cvt_into (self ) -> Vec <u8 > {
250
+ fn convert_into (self ) -> Vec <u8 > {
225
251
self . into_bytes ()
226
252
}
227
253
}
228
254
229
255
fn main () {
230
256
let a = format! (" hello" );
231
- let b : & [u8 ] = a . cvt_as ();
232
- let c : & str = a . cvt_as ();
233
- let d : Vec <u8 > = a . cvt_into ();
257
+ let b : & [u8 ] = a . convert_as ();
258
+ let c : & str = a . convert_as ();
259
+ let d : Vec <u8 > = a . convert_into ();
234
260
}
235
261
```
236
262
@@ -242,7 +268,7 @@ impl Path {
242
268
fn join_path_inner(&self, p: &Path) -> PathBuf { ... }
243
269
244
270
pub fn join_path<P: As<Path>>(&self, p: &P) -> PathBuf {
245
- self.join_path_inner(p.cvt_as ())
271
+ self.join_path_inner(p.convert_as ())
246
272
}
247
273
}
248
274
```
@@ -295,16 +321,19 @@ So a rough, preliminary convention would be the following:
295
321
in this RFC. An * ad hoc conversion trait* is a trait providing an ad
296
322
hoc conversion method.
297
323
298
- * Use ad hoc conversion methods for "natural" conversions that should
299
- have easy names and good discoverability. A conversion is "natural"
300
- if you'd call it directly on the type in normal code; "unnatural"
301
- conversions usually come from generic programming.
324
+ * Use ad hoc conversion methods for "natural", * outgoing* conversions
325
+ that should have easy method names and good discoverability. A
326
+ conversion is "natural" if you'd call it directly on the type in
327
+ normal code; "unnatural" conversions usually come from generic
328
+ programming.
302
329
303
330
For example, ` to_string ` is a natural conversion for ` str ` , while
304
331
` into_string ` is not; but the latter is sometimes useful in a
305
332
generic context -- and that's what the generic conversion traits can
306
333
help with.
307
334
335
+ * On the other hand, favor ` From ` for all conversion constructors.
336
+
308
337
* Introduce ad hoc conversion * traits* if you need to provide a
309
338
blanket ` impl ` of an ad hoc conversion method, or need special
310
339
functionality. For example, ` to_string ` needs a trait so that every
@@ -323,6 +352,18 @@ So a rough, preliminary convention would be the following:
323
352
* Use the "inner function" pattern mentioned above to avoid code
324
353
bloat.
325
354
355
+ ## Prelude changes
356
+
357
+ * All* of the conversion traits are added to the prelude. There are two
358
+ reasons for doing so:
359
+
360
+ * For ` As ` /` To ` /` Into ` , the reasoning is similar to the inclusion of
361
+ ` PartialEq ` and friends: they are expected to appear ubiquitously as
362
+ bounds.
363
+
364
+ * For ` From ` , bounds are somewhat less common but the use of the
365
+ ` from ` constructor is expected to be rather widespread.
366
+
326
367
# Drawbacks
327
368
328
369
There are a few drawbacks to the design as proposed:
0 commit comments