Is there any real difference between `FromStr` and `TryFrom<&str>`? - rust

Is there any real difference between FromStr and TryFrom<&str>?
From the definitions in the documentation, they look identical once you substitute &str for T in TryFrom:
pub trait FromStr {
type Err;
fn from_str(s: &str) -> Result<Self, Self::Err>;
}
pub trait TryFrom<T> {
type Error;
fn try_from(value: T) -> Result<Self, Self::Error>;
}
Then there is parse:
FromStr’s from_str method is often used implicitly, through str’s
parse method.
But if we look at its implementation, we see that it does not do anything beyond providing a slightly shorter way of calling from_str:
pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
FromStr::from_str(self)
}
If you look at TryFrom's library implementations, then it is almost exclusively composed of numerical conversions, though there is also:
impl<'_, T, const N: usize> TryFrom<&'_ [T]> for [T; N] where
T: Copy,
type Error = TryFromSliceError
which is reminiscent of
impl FromStr for String {
type Err = core::convert::Infallible;
#[inline]
fn from_str(s: &str) -> Result<String, Self::Err> {
Ok(String::from(s))
}
}
Converting the example implementation of FromStr from the docs to TryFrom is trivial.
There was a similar question on Reddit to which the best answer seems to be "just implement both".
Finally there is this similar question though it uses the wrong type and the Serde context is a distraction.
So:
Is there any real difference between FromStr and TryFrom<&str>?
What is current best practice regarding their use?
Is there any plan for the future towards improving the situation?

FromStr provides more type information to the compiler, and thus may help inference. It is also more specific, and thus helps the reader. When the intent is to parse the string, I would use FromStr, because it can be used via the parse() method. If this is just for conversion, I would implement TryFrom<&str>.
Also remember that as stated in What is the difference between the FromStr and TryFrom<String> traits?, FromStr preceeded TryFrom.
Is there any plan for the future towards improving the situation?
Nothing that I'm aware of.

Related

By-value methods on trait objects [duplicate]

I was writing some code and had a trait with a method that takes self by value. I want to call this method on a Box'd trait object (consuming the Box and its value). Is this possible? If so, how?
In terms of code, a minimal example looks like the following (incomplete) code:
trait Consumable {
fn consume(self) -> u64;
}
fn consume_box(ptr: Box<dyn Consumable>) -> u64 {
//what can I put here?
}
My question is how to fill in the function consume_box with the specified signature so that the value returned is whatever value would be gotten by calling consume on the Box'd value.
I had initially written
ptr.consume()
as the body of the function, though I realize this isn't quite the right idea, since it doesn't get across the fact that I want the Box to be consumed, not just its contents, but it's the only thing I could think of. This does not compile, giving an error:
cannot move a value of type dyn Consumable: the size of dyn Consumable cannot be statically determined
This was somewhat surprising to me, being new to Rust, I had thought that maybe the self argument was passed similarly to an rvalue reference in C++ (which is really what I want - in C++, I would probably implement this by a method with the signature virtual std::uint64_t consume() &&, letting a std::unique_ptr clean up the moved-from object via a virtual destructor), but I guess Rust is truly passing by value, moving the argument into place prior - so it's reasonable that it rejects the code.
Trouble is, I'm not sure how to get the behavior I want, where I can consume a Box'd trait object. I tried adding a method to the trait with a default implementation, thinking that might get me something useful in the vtable:
trait Consumable {
fn consume(self) -> u64;
fn consume_box(me: Box<Self>) -> u64 {
me.consume()
}
}
However, this then yields the error
the trait Consumable cannot be made into an object
when I mention the Box<dyn Consumable> type - which is not so surprising, since the compiler figuring out what to do with a function whose argument type varied with Self would have been miraculous.
Is it possible to implement the function consume_box with the provided signature - even modifying the trait if necessary?
If it's useful, more specifically, this is part of a sort of representation of some mathematical expressions - maybe a toy model would be that specific implementations that look roughly like:
impl Consumable for u64 {
fn consume(self) -> u64 {
self
}
}
struct Sum<A, B>(A, B);
impl<A: Consumable, B: Consumable> Consumable for Sum<A, B> {
fn consume(self) -> u64 {
self.0.consume() + self.1.consume()
}
}
struct Product<A, B>(A, B);
impl<A: Consumable, B: Consumable> Consumable for Product<A, B> {
fn consume(self) -> u64 {
self.0.consume() * self.1.consume()
}
}
fn parse(&str) -> Option<Box<dyn Consumable> > {
//do fancy stuff
}
where, for the most part, things are plain old data (but arbitrarily large blocks of it, potentially, due to the generics), but to also have this be compatible with passing around more opaque handles to these sorts of things - hence the desire to be able to work with Box<dyn Consumable>. At least at the language level, this is a good model of what sort of things I'm up to - the only resources owned by these objects are pieces of memory (nothing to do with multithreading and no self-referential shenanigans) - although this model doesn't capture that the use case I have is one where it's useful for the implementation to consume the object rather than to merely read it nor does it appropriately model that I want an "open" class of possible segments rather than a finite set of possiblities (making it hard to do something like an enum that represents a tree directly) - hence why I'm asking about passing by value rather than trying to rewrite it to pass by reference.
You can consume from a Box<dyn Trait> if the parameter is self: Box<Self>:
trait Consumable {
fn consume(self) -> u64;
fn consume_box(self: Box<Self>) -> u64;
}
struct Foo;
impl Consumable for Foo {
fn consume(self) -> u64 {
42
}
fn consume_box(self: Box<Self>) -> u64 {
self.consume()
}
}
fn main() {
let ptr: Box<dyn Consumable> = Box::new(Foo);
println!("result is {}", ptr.consume_box());
}
However, this does have the annoying boilerplate of having to implement consume_box() for each implementation; trying to define a default implementation will run into a "cannot move value of type Self - the size of Self cannot be statically determined" error.
In general though this is not supported. A dyn Consumable represents an unsized type which are very limited except through indirection (via references or Box-like structs). It works for the above case because Box is a bit special (is the only dispatchable type you can take ownership from) and the consume_box method does not put self on the stack as a dynamic trait object (only in each implementation where its concrete).
However there is RFC 1909: Unsized RValues which hopes to loosen some of these limits. One being able to pass unsized function parameters, like self in this case. The current implementation of this RFC accepts your initial code when compiled on nightly with unsized_fn_params:
#![feature(unsized_fn_params)]
trait Consumable {
fn consume(self) -> u64;
}
struct Foo;
impl Consumable for Foo {
fn consume(self) -> u64 {
42
}
}
fn main () {
let ptr: Box<dyn Consumable> = Box::new(Foo);
println!("result is {}", ptr.consume());
}
See on the playground.
I believe
trait Consumable {
fn consume(self) -> u64;
}
fn consume_box(val: impl Consumable) -> u64 {
val.consume()
}
might do what you want. I'm all but a Rust expert - or C++ expert for that matter -, but I think it should be working pretty much like the move-semantics in C++ you mentioned in terms of memory behavior. From what I understand it is a form of generic where Rust implements the Function for every type you call it with.
If you don't use nightly Rust, I wrote a macro here. It generates the second trait function automatically.
trait Consumable {
fn consume(self) -> u64;
fn consume_box(me: Box<Self>) -> u64 ;
}

What enables a function trait type to be used where an fn type is expected?

What enables a function trait type (std::ops::Fn) to be used where an fn type (e.g. closure, function definition, fn pointer type) is expected?
fn take_closure<F: Fn(u32) -> u32>(_f: F) {}
fn id(x: u32) -> u32 {
x
}
fn main() {
take_closure(id);
}
Is it:
an impl of Fn for each corresponding fn type?
or a coercion, like the the one from Fn to fn
I'm asking more about mental model than about concrete implementation.
Edit
updated the example, previously the example showed conversion the other way. Sorry about that. I created a separate question to ask about conversion the other way: What enables a closure type to be used where a function pointer type to be used in Rust?
It is the former (the implementations are produced by the compiler). From the documentation.
all safe function pointers implement Fn, FnMut, and FnOnce. This works because these traits are specially known to the compiler.
I sometimes think of this as fn is a Fn which does not capture anything from the environment.

Rust shorthand for Result<type, Box<dyn std::error::Error>>

When doing error catching I usually make a function return a result. But I feel like writing Result<type, Box<...>> everytime is really verbose, is there some built-in shorthand for this?
fn something() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
You can just define a type alias with generic arguments. Many crates do like this:
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
fn something() -> Result<()> {
Ok(())
}
The anyhow crate, written by the author of serde, is designed around an ergonomic alternative to Box<dyn std::error::Error> called anyhow::Error. It defines anyhow::Result<T> as alias for Result<T, anyhow::Error>:
fn something() -> anyhow::Result<()> {
Ok(())
}
The downside is that it's an external crate, although a very popular and well-tested one.
The upside is that you get good ergonomics, additional features (such as context() and with_context() on Result), as well as non-trivial optimizations - anyhow::Error is a narrow pointer rather than a wide one, so your Results are smaller and more efficient compared to Box<dyn Error>.

What are the pros and cons of impl TryFrom<Bar> for Foo vs impl From<Bar> for Result<Foo, ()> for fallible conversions?

Starting from Rust 1.34, we can write fallible conversions between types by implementing the TryFrom trait:
struct Foo(i32);
struct Bar;
impl TryFrom<Bar> for Foo {
type Error = ();
fn try_from(_b: Bar) -> Result<Foo, ()> {
Ok(Foo(42))
}
}
In Rust 1.41, the orphan rule has been relaxed so we can also write:
struct Foo(i32);
struct Bar;
impl From<Bar> for Result<Foo, ()> {
fn from(_b: Bar) -> Result<Foo, ()> {
Ok(Foo(42))
}
}
According to this trial both solutions seem to work equally well.
What are the pros and cons of having either or both approach? How to choose from the two?
This question is important to the ecosystem. For example, a crate writer needs advice on whether to support TryFrom, From or both. A macro writer will need to know if it needs to handle both cases, etc. This depends on the status of the ecosystem today, and can't be answered easily.
In TryFrom, the error is an associated type—it is fixed by the type Bar. This is not the case for From, and indeed you could implement From for more than one error type. Unless you intend to do that (which is rather strange), you should stick to TryFrom.

Take any type that can yield a char iterator, plus &str

I want to write a function tokenize that takes chars from an iterator. Like this:
fn tokenize<F: IntoIterator<Item=char>>(file: F)
If I want to use a &str with this function, I can do it like this:
tokenize("foo".chars())
That works OK.
Now, I'd like to avoid that .chars() specifically for type &str, since I know that, if I'm given a &str, I can make it what I want by calling .chars().
I tried declaring a new trait, IntoChars, and implement it for &str:
trait IntoChars {
type T: Iterator<Item=char>;
fn into_chars(&self) -> Self::T;
}
impl<'a> IntoChars for &'a str {
type T = Chars<'a>;
fn into_chars(&self) -> Self::T {
self.chars()
}
}
If then I make my function like this:
tokenize<F: IntoChars>(file: F)
it works. Nice! But I want to implement IntoChars also for any type that can give me chars, ie. is IntoIterator<Item=char>.
impl<T: IntoIterator<Item=char>> IntoChars for T {
type T = T::IntoIter;
fn into_chars(self) -> Self::T {
self.into_iter()
}
}
That doesn't work. For two reasons:
IntoIter::into_iter takes a self, but IntoChars::into_chars takes a &self. This is specifically because I don't want to consume &str when calling its into_chars method unnecessarily. Is there any way to achieve both?
OK, let's say that I make IntoChars::into_chars take a self. This still doesn't work; I get: error: conflicting implementations for trait `IntoChars` [E0119]. But if I remove the impl<'a> IntoChars for &'a str, I get error: the trait `core::iter::Iterator` is not implemented for the type `&str`. Why is is conflicting then?
Any way I can achieve this?
Let's look at your two implementations, which I've rewritten in the more verbose form:
impl<T> IntoChars for T
where T: IntoIterator<Item = char>
impl<'a> IntoChars for &'a str
What should the compiler do when whoever owns either the trait IntoIterator or the type &str decides to implement IntoIterator for &str? All of the sudden, you'd have conflicting implementations for the same trait; There are two ways that IntoChars would be implemented for &str.
Other keywords for this problem are trait coherence and orphan rules.
To be able to compile this, you'd need impl specialization, which is an RFC that has not been accepted yet.

Resources