Skip to content

Commit adc2547

Browse files
committed
Add TryFrom and TryInto traits
1 parent 80152a3 commit adc2547

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed

text/0000-try-from.md

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
- Feature Name: try_from
2+
- Start Date: 2016-03-10
3+
- RFC PR:
4+
- Rust Issue:
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
The standard library provides the `From` and `Into` traits as standard ways to
10+
convert between types. However, these traits only support *infallable*
11+
conversions. This RFC proposes the addition of `TryFrom` and `TryInto` traits
12+
to support these use cases in a standard way.
13+
14+
# Motivation
15+
[motivation]: #motivation
16+
17+
Fallible conversions are fairly common, and a collection of ad-hoc traits has
18+
arisen to support them, both [within the standard library][from-str] and [in
19+
third party crates][into-connect-params]. A standardized set of traits
20+
following the pattern set by `From` and `Into` will ease these APIs by
21+
providing a standardized interface as we expand the set of fallible
22+
conversions.
23+
24+
One specific avenue of expansion that has been frequently requested is fallible
25+
integer conversion traits. Conversions between integer types may currently be
26+
performed with the `as` operator, which will silently truncate the value if it
27+
is out of bounds of the target type. Code which needs to down-cast values must
28+
manually check that the cast will succeed, which is both tedious and error
29+
prone. A fallible conversion trait reduces code like this:
30+
31+
```rust
32+
let value: isize = ...;
33+
34+
let value: u32 = if value < 0 || value > u32::max_value() as isize {
35+
return Err(BogusCast);
36+
} else {
37+
value as u32
38+
};
39+
```
40+
41+
to simply:
42+
43+
```rust
44+
let value: isize = ...;
45+
let value: u32 = try!(value.try_into());
46+
```
47+
48+
# Detailed design
49+
[design]: #detailed-design
50+
51+
Two traits will be added to the `core::convert` module:
52+
53+
```rust
54+
pub trait TryFrom<T>: Sized {
55+
type Err;
56+
57+
fn try_from(t: T) -> Result<Self, Self::Err>;
58+
}
59+
60+
pub trait TryInto<T>: Sized {
61+
type Err;
62+
63+
fn try_into(self) -> Result<T, Self::Err>;
64+
}
65+
```
66+
67+
In a fashion similar to `From` and `Into`, a blanket implementation of `TryInto`
68+
is provided for all `TryFrom` implementations:
69+
70+
```rust
71+
impl<T, U> TryInto<U> for T where U: TryFrom<T> {
72+
type Error = U::Err;
73+
74+
fn try_into(self) -> Result<U, Self::Err> {
75+
U::try_from(self)
76+
}
77+
}
78+
```
79+
80+
In addition, implementations of `TryFrom` will be provided to convert between
81+
*all combinations* of integer types:
82+
83+
```rust
84+
#[derive(Debug)]
85+
pub struct TryFromIntError(());
86+
87+
impl fmt::Display for TryFromIntError {
88+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
89+
fmt.write_str(self.description())
90+
}
91+
}
92+
93+
impl Error for TryFromIntError {
94+
fn description(&self) -> &str {
95+
"out of range integral type conversion attempted"
96+
}
97+
}
98+
99+
impl TryFrom<usize> for u8 {
100+
type Err = TryFromIntError;
101+
102+
fn try_from(t: usize) -> Result<u8, TryFromIntError> {
103+
// ...
104+
}
105+
}
106+
107+
// ...
108+
```
109+
110+
This notably includes implementations that are actually infallible, including
111+
implementations between a type and itself. A common use case for these kinds
112+
of conversions is when interacting with a C API and converting, for example,
113+
from a `u64` to a `libc::c_long`. `c_long` may be `u32` on some platforms but
114+
`u64` on others, so having an `impl TryFrom<u64> for u64` ensures that
115+
conversions using these traits will compile on all architectures. Similarly, a
116+
conversion from `usize` to `u32` may or may not be fallible depending on the
117+
target architecture.
118+
119+
The standard library provides a reflexive implementation of the `From` trait
120+
for all types: `impl<T> From<T> for T`. We could similarly provide a "lifting"
121+
implementation of `TryFrom`:
122+
123+
```rust
124+
impl<T, U: From<T>> TryFrom<T> for U {
125+
type Err = Void;
126+
127+
fn try_from(t: T) -> Result<U, Void> {
128+
Ok(U::from(t))
129+
}
130+
}
131+
```
132+
133+
However, this implementation would directly conflict with our goal of having
134+
uniform `TryFrom` implementations between all combinations of integer types. In
135+
addition, it's not clear what value such an implementation would actually
136+
provide, so this RFC does *not* propose its addition.
137+
138+
# Drawbacks
139+
[drawbacks]: #drawbacks
140+
141+
It is unclear if existing fallible conversion traits can backwards-compatibly
142+
be subsumed into `TryFrom` and `TryInto`, which may result in an awkward mix of
143+
ad-hoc traits in addition to `TryFrom` and `TryInto`.
144+
145+
# Alternatives
146+
[alternatives]: #alternatives
147+
148+
We could avoid general traits and continue making distinct conversion traits for
149+
each use case.
150+
151+
# Unresolved questions
152+
[unresolved]: #unresolved-questions
153+
154+
Are `TryFrom` and `TryInto` the right names? There is some precedent for the
155+
`try_` prefix: `TcpStream::try_clone`, `Mutex::try_lock`, etc.
156+
157+
What should be done about `FromStr`, `ToSocketAddrs`, and other ad-hoc fallible
158+
conversion traits? An upgrade path may exist in the future with specialization,
159+
but it is probably too early to say definitively.
160+
161+
Should `TryFrom` and `TryInto` be added to the prelude? This would be the first
162+
prelude addition since the 1.0 release.
163+
164+
[from-str]: https://doc.rust-lang.org/1.7.0/std/str/trait.FromStr.html
165+
[into-connect-params]: http://sfackler.github.io/rust-postgres/doc/v0.11.4/postgres/trait.IntoConnectParams.html

0 commit comments

Comments
 (0)