From trait called inside a generic function - rust

I am using the From trait to convert an i32 to a structure of my own. I use this conversion in a generic function do_stuff that doesn't compile:
use std::convert::*;
struct StoredValue {
val: i32,
}
impl From<i32> for StoredValue {
fn from(value: i32) -> StoredValue {
return StoredValue {val: value};
}
}
/// Generic function that stores a value and do stuff
fn do_stuff<T>(value: T) -> i32 where T: From<T> {
let result = StoredValue::from(value);
// .... do stuff and
return 0;
}
fn main () {
let result = do_stuff(0); // call with explicit type
}
and the compilation error:
main.rs:15:18: 15:35 error: the trait `core::convert::From<T>` is not implemented for the type `StoredValue` [E0277]
main.rs:15 let result = StoredValue::from(value);
Does it make sense to implement a generic version of From<T> for StoredValue?

Your generic function is saying, "I accept any type that implements being created from itself." Which isn't what you want.
There's a few things you could be wanting to say:
"I accept any type that can be converted into an i32 so that I can create a StoredValue." This works because you know StoredValue implements From<i32>.
fn do_stuff<T>(value: T) -> i32 where T: Into<i32> {
let result = StoredValue::from(value.into());
// ...
}
Or, "I accept any type that can be converted into a StoredValue." There is a handy trait that goes along with the From<T> trait, and it's called Into<T>.
fn do_stuff<T>(value: T) -> i32 where T: Into<StoredValue> {
let result = value.into();
// ...
}
The way to remember how/when to use these two traits that go hand in hand is this:
Use Into<T> when you know what you want the end result to be, i.e from ?->T
Use From<T> when you know what you have to start with, but not the end result, i.e. T->?
The reason these two traits can go hand in hand together, is if you have a T that implements Into<U>, and you have V that implements From<U> you can get from a T->U->V.
The Rust std lib has such a conversion already baked in that says, "Any type T that implements From<U>, than U implements Into<T>."
Because of this, when you implemented From<i32> for StoredValue you can assume there is a Into<StoredValue> for i32.

To make do_stuff() work, it must be possible to convert type T into StoredValue. So its declaration should be
fn do_stuff<T>(value: T) -> i32 where StoredValue: From<T> {
Edit: I agree with Shepmaster that that should better be
fn do_stuff<T>(value: T) -> i32 where T: Into<StoredValue> {
let result = value.into();
// ...
Since there is a generic implementation that turns T: From<U> into U: Into<T>, this allows to use both kinds of conversions, those implementing From and those implementing Into. With my first version only conversions implementing From would work.

Related

Can't solve lifetime problem in simple method

I'm brand new at Rust, coming from Java and I experience some difficulties with owenership and lifetimes. I'd like to do some formal calculus but obviously I'm not doing things the right way... Can you please show me why?
In my code I define those:
pub trait Function {
fn differentiate(&self) -> Box<dyn Function>;
}
pub struct Add<'a>(&'a Box<dyn Function>, &'a Box<dyn Function>);
impl<'a> Function for Add<'a> {
fn differentiate(&self) -> Box<dyn Function> {
let x = self.0.differentiate();
let y = self.1.differentiate();
let add = Add(&x, &y);
Box::new(add)
}
Compiler tells me I have a borrowing problem with x and y, I understand why but can't figure out how to solve it; I tried to set let x: Box<dyn Function + 'a> = ... but then I got lifetime problems on defining add and on the last line:
expected `Box<(dyn Function + 'static)>`
found `Box<dyn Function>`
You cannot return an object that references local variables.
This is nothing special to Rust, it is like that in every language that has references (Java doesn't, in Java everything is a reference counting smart pointer). Writing this in C/C++ would be undefined behaviour. The borrow checker is here to prevent undefined behaviour, so it rightfully complains.
Here is a wild guess of what you might have wanted to do.
I'm unsure why you use references here, so I removed them. Your code looks like Add should own its members.
pub trait Function {
fn differentiate(&self) -> Box<dyn Function>;
}
pub struct Add(Box<dyn Function>, Box<dyn Function>);
impl Function for Add {
fn differentiate(&self) -> Box<dyn Function> {
let x = self.0.differentiate();
let y = self.1.differentiate();
let add = Add(x, y);
Box::new(add)
}
}
An alternative design would be to require differentiable functions to be clonable (because you'll probably want to be able to use them in different places), and avoid dynamic dispatch (and the indirection required by trait objects) altogether. Here is the implementation of two simple operations as an example.
trait Differentiable: Clone {
type Output;
fn differentiate(&self) -> Self::Output;
}
#[derive(Clone)]
struct Add<L, R>(L, R);
impl<L: Differentiable, R: Differentiable> Differentiable for Add<L, R> {
type Output = Add<L::Output, R::Output>;
fn differentiate(&self) -> Self::Output {
Add(self.0.differentiate(), self.1.differentiate())
}
}
#[derive(Clone)]
struct Mul<L, R>(L, R);
impl<L: Differentiable, R: Differentiable> Differentiable for Mul<L, R> {
type Output = Add<Mul<L::Output, R>, Mul<L, R::Output>>;
fn differentiate(&self) -> Self::Output {
Add(Mul(self.0.differentiate(), self.1.clone()), Mul(self.0.clone(), self.1.differentiate()))
}
}
Note that this easily allows adding useful constraints, such as making them callable (if you actually want to be able to evaluate them) or stuff like that. These, alongside with the identify function and the constant function should probably be enough for you to "create" polynomial calculus.
The simplest is to remove the references, because your Box is a smart pointer. So:
pub trait Function {
fn differentiate(&self) -> Box<dyn Function>;
}
pub struct Add(Box<dyn Function>, Box<dyn Function>);
impl Function for Add {
fn differentiate(&self) -> Box<dyn Function> {
let x = self.0.differentiate();
let y = self.1.differentiate();
Box::new(Add(x, y))
}
}
I think what you are trying to return a type after adding two types that implement differentiation.
There are a few different ways to think about this... Here's one:
pub trait Differentiable {
type Result;
fn differentiate(self) -> Self::Result;
}
pub struct Add<OP1, OP2>(OP1, OP2);
impl<OP1, OP2> Differentiable for Add<OP1, OP2>
where
OP1: Differentiable,
OP2: Differentiable,
{
type Result = Add<OP1::Result, OP2::Result>;
fn differentiate(self) -> Self::Result {
let x = self.0.differentiate();
let y = self.1.differentiate();
Add(x, y)
}
}

How to return an anonymous type from a trait method without using Box?

I have an extension trait whose methods are just shorthands for adapters/combinators:
fn foo(self) -> ... { self.map(|i| i * 2).foo().bar() }
The return type of Trait::foo() is some nested Map<Foo<Bar<Filter..., including closures, and is therefor anonymous for all practical purposes. My problem is how to return such a type from a trait method, preferably without using Box.
impl Trait in return position would be the way to go, yet this feature is not implemented for trait methods yet.
Returning a Box<Trait>is possible, yet I don't want to allocate for every adapter shorthanded by the trait.
I can't put the anonymous type into a struct and return that, because struct Foo<T> { inner: T } can't be implemented (I promise an impl for all T, yet only return a specific Foo<Map<Filter<Bar...).
Existential types would probably solve the above problem, yet they won't be implemented for some time.
I could also just avoid the problem and use a macro or a freestanding function; this also feels unhygienic, though.
Any more insights?
What is the correct way to return an Iterator (or any other trait)? covers all the present solutions. The one you haven't used is to replace closures with function pointers and then use a type alias (optionally wrapping in a newtype). This isn't always possible, but since you didn't provide a MCVE of your code, we can't tell if this will work for you or not:
use std::iter;
type Thing<T> = iter::Map<iter::Filter<T, fn(&i32) -> bool>, fn(i32) -> i32>;
trait IterExt: Iterator<Item = i32> {
fn thing(self) -> Thing<Self>
where
Self: Sized + 'static,
{
// self.filter(|&v| v > 10).map(|v| v * 2)
fn a(v: &i32) -> bool { *v > 10 }
fn b(v: i32) -> i32 { v * 2 }
self.filter(a as fn(&i32) -> bool).map(b as fn(i32) -> i32)
}
}
impl<I> IterExt for I
where
I: Iterator<Item = i32>,
{}
fn main() {}
Honestly, in these cases I would create a newtype wrapping the boxed trait object. That way, I have the flexibility to internally re-implement it with a non-boxed option in an API-compatible fashion when it becomes practical to do so.

Get generic trait from ordinal one without Self type?

I have two traits, one ordinal (Foo), another generic (TypedFoo<T>). I have several structures, each of them have both traits implemented.
Is it possible to convert from Foo to TypedFoo<T>, without converting to an intermediate structure?
trait Foo {
fn f(&mut self);
}
trait TypedFoo<T> {
fn get(&self) -> T;
}
#[derive(Clone)]
struct Data(i32);
impl Foo for Data {
fn f(&mut self) {
self.0 += 1;
}
}
impl TypedFoo<Data> for Data {
fn get(&self) -> Data {
self.clone()
}
}
//struct Data2(f64);
//impl Foo for Data2...
//impl TypedFoo<Data2> for Data2..
fn main() {
let v: Vec<Box<Foo>> = vec![Box::new(Data(1))];
}
I can change Foo to this:
trait Foo {
fn f(&mut self);
fn get_self(&self) -> &Any;
}
Then get v[0].get_self() downcast_ref to Data, and then Data to &TypedFoo<Data>.
But is it possible to get &TypedFoo<Data> from &Foo without knowing "data type", some analog of Any but for a trait.
I imagine syntax like this:
let foo: &Foo = ...;
if let Some(typed_foo) = foo.cast::<Data>() {
}
My question is different from Can I cast between two traits?
because I have one generic and one ordinal trait. If I had two ordinal traits then the solution would be as simple as:
trait Foo {
fn f(&mut self);
fn as_typed_foo(&self) -> &TypedFoo;
}
Since TypedFoo is generic, none of the answers in that question help me. One possible solution could be:
trait Foo {
fn f(&mut self);
fn cast(&mut self, type_id: ::std::any::TypeId) -> Option<*mut ::std::os::raw::c_void>;
}
I am not sure how safe it is to cast *mut TypedFoo<T> -> *mut ::std::os::raw::c_void and then back to *mut TypedFoo<T>.
The signature of the function that you want is
fn convert<T>(x: &Box<Foo>) -> &TypedFoo<T>
To type check this signature compiler must know that the type inside Box implements TypedFoo<T> for some T. But conversion into trait-object erases information about the real type. Which means that it is impossible to statically type check signature of this function.
So we need to do it dynamically and if we want to use types a current crate doesn't know about, we'll need to resort to unsafe.
One option is to limit a set of types, which can be used in TypedFoo, and provide conversion functions in the Foo trait. This allows to avoid unsafe.
Playground link
Second option is to add to trait Foo a function, which returns a slice of pairs (TypeId, *const ()). The pointer is a type erased pointer to function, which does actual conversion. Conversion function searches required type identifier and executes corresponding function.
Playground link
For the sake of demonstration I used Vec instead of slice in conversion_registrar. But it shouldn't be too hard to change return type to &'static [(TypeId, *const ())], using lazy_static crate.

Understanding the 'self' parameter in the context of trait implementations

When implementing a trait, we often use the keyword self, a sample is as follows. I want to understand the representation of the many uses of self in this code sample.
struct Circle {
x: f64,
y: f64,
radius: f64,
}
trait HasArea {
fn area(&self) -> f64; // first self: &self is equivalent to &HasArea
}
impl HasArea for Circle {
fn area(&self) -> f64 { //second self: &self is equivalent to &Circle
std::f64::consts::PI * (self.radius * self.radius) // third:self
}
}
My understanding is:
The first self: &self is equivalent to &HasArea.
The second self: &self is equivalent to &Circle.
Is the third self representing Circle? If so, if self.radius was used twice, will that cause a move problem?
Additionally, more examples to show the different usage of the self keyword in varying context would be greatly appreciated.
You're mostly right.
The way I think of it is that in a method signature, self is a shorthand:
impl S {
fn foo(self) {} // equivalent to fn foo(self: S)
fn foo(&self) {} // equivalent to fn foo(self: &S)
fn foo(&mut self) {} // equivalent to fn foo(self: &mut S)
}
It's not actually equivalent since self is a keyword and there are some special rules (for example for lifetime elision), but it's pretty close.
Back to your example:
impl HasArea for Circle {
fn area(&self) -> f64 { // like fn area(self: &Circle) -> ...
std::f64::consts::PI * (self.radius * self.radius)
}
}
The self in the body is of type &Circle. You can't move out of a reference, so self.radius can't be a move even once. In this case radius implements Copy, so it's just copied out instead of moved. If it were a more complex type which didn't implement Copy then this would be an error.
You are mostly correct.
There is a neat trick to let the compiler tell you the type of variables rather than trying to infer them: let () = ...;.
Using the Playground I get for the 1st case:
9 | let () = self;
| ^^ expected &Self, found ()
and for the 2nd case:
16 | let () = self;
| ^^ expected &Circle, found ()
The first case is actually special, because HasArea is not a type, it's a trait.
So what is self? It's nothing yet.
Said another way, it poses for any possible concrete type that may implement HasArea. And thus the only guarantee we have about this trait is that it provides at least the interface of HasArea.
The key point is that you can place additional bounds. For example you could say:
trait HasArea: Debug {
fn area(&self) -> f64;
}
And in this case, Self: HasArea + Debug, meaning that self provides both the interfaces of HasArea and Debug.
The second and third cases are much easier: we know the exact concrete type for which the HasArea trait is implemented. It's Circle.
Therefore, the type of self in the fn area(&self) method is &Circle.
Note that if the type of the parameter is &Circle then it follows that in all its uses in the method it is &Circle. Rust has static typing (and no flow-dependent typing) so the type of a given binding does not change during its lifetime.
Things can get more complicated, however.
Imagine that you have two traits:
struct Segment(Point, Point);
impl Segment {
fn length(&self) -> f64;
}
trait Segmentify {
fn segmentify(&self) -> Vec<Segment>;
}
trait HasPerimeter {
fn has_perimeter(&self) -> f64;
}
Then, you can implement HasPerimeter automatically for all shapes that can be broken down in a sequence of segments.
impl<T> HasPerimeter for T
where T: Segmentify
{
// Note: there is a "functional" implementation if you prefer
fn has_perimeter(&self) -> f64 {
let mut total = 0.0;
for s in self.segmentify() { total += s.length(); }
total
}
}
What is the type of self here? It's &T.
What's T? Any type that implements Segmentify.
And therefore, all we know about T is that it implements Segmentify and HasPerimeter, and nothing else (we could not use println("{:?}", self); because T is not guaranteed to implement Debug).

How do you actually use dynamically sized types in Rust?

In theory, Dynamically-Sized Types (DST) have landed and we should now be able to use dynamically sized type instances. Practically speaking, I can neither make it work, nor understand the tests around it.
Everything seems to revolve around the Sized? keyword... but how exactly do you use it?
I can put some types together:
// Note that this code example predates Rust 1.0
// and is no longer syntactically valid
trait Foo for Sized? {
fn foo(&self) -> u32;
}
struct Bar;
struct Bar2;
impl Foo for Bar { fn foo(&self) -> u32 { return 9u32; }}
impl Foo for Bar2 { fn foo(&self) -> u32 { return 10u32; }}
struct HasFoo<Sized? X> {
pub f:X
}
...but how do I create an instance of HasFoo, which is DST, to have either a Bar or Bar2?
Attempting to do so always seems to result in:
<anon>:28:17: 30:4 error: trying to initialise a dynamically sized struct
<anon>:28 let has_foo = &HasFoo {
I understand broadly speaking that you can't have a bare dynamically sized type; you can only interface with one through a pointer, but I can't figure out how to do that.
Disclaimer: these are just the results of a few experiments I did, combined with reading Niko Matsakis's blog.
DSTs are types where the size is not necessarily known at compile time.
Before DSTs
A slice like [i32] or a bare trait like IntoIterator were not valid object types because they do not have a known size.
A struct could look like this:
// [i32; 2] is a fixed-sized vector with 2 i32 elements
struct Foo {
f: [i32; 2],
}
or like this:
// & is basically a pointer.
// The compiler always knows the size of a
// pointer on a specific architecture, so whatever
// size the [i32] has, its address (the pointer) is
// a statically-sized type too
struct Foo2<'a> {
f: &'a [i32],
}
but not like this:
// f is (statically) unsized, so Foo is unsized too
struct Foo {
f: [i32],
}
This was true for enums and tuples too.
With DSTs
You can declare a struct (or enum or tuple) like Foo above, containing an unsized type. A type containing an unsized type will be unsized too.
While defining Foo was easy, creating an instance of Foo is still hard and subject to change. Since you can't technically create an unsized type by definition, you have to create a sized counterpart of Foo. For example, Foo { f: [1, 2, 3] }, a Foo<[i32; 3]>, which has a statically known size and code some plumbing to let the compiler know how it can coerce this into its statically unsized counterpart Foo<[i32]>. The way to do this in safe and stable Rust is still being worked on as of Rust 1.5 (here is the RFC for DST coercions for more info).
Luckily, defining a new DST is not something you will be likely to do, unless you are creating a new type of smart pointer (like Rc), which should be a rare enough occurrence.
Imagine Rc is defined like our Foo above. Since it has all the plumbing to do the coercion from sized to unsized, it can be used to do this:
use std::rc::Rc;
trait Foo {
fn foo(&self) {
println!("foo")
}
}
struct Bar;
impl Foo for Bar {}
fn main() {
let data: Rc<Foo> = Rc::new(Bar);
// we're creating a statically typed version of Bar
// and coercing it (the :Rc<Foo> on the left-end side)
// to as unsized bare trait counterpart.
// Rc<Foo> is a trait object, so it has no statically
// known size
data.foo();
}
playground example
?Sized bound
Since you're unlikely to create a new DST, what are DSTs useful for in your everyday Rust coding? Most frequently, they let you write generic code that works both on sized types and on their existing unsized counterparts. Most often these will be Vec/[] slices or String/str.
The way you express this is through the ?Sized "bound". ?Sized is in some ways the opposite of a bound; it actually says that T can be either sized or unsized, so it widens the possible types we can use, instead of restricting them the way bounds typically do.
Contrived example time! Let's say that we have a FooSized struct that just wraps a reference and a simple Print trait that we want to implement for it.
struct FooSized<'a, T>(&'a T)
where
T: 'a;
trait Print {
fn print(&self);
}
We want to define a blanket impl for all the wrapped T's that implement Display.
impl<'a, T> Print for FooSized<'a, T>
where
T: 'a + fmt::Display,
{
fn print(&self) {
println!("{}", self.0)
}
}
Let's try to make it work:
// Does not compile. "hello" is a &'static str, so self print is str
// (which is not sized)
let h_s = FooSized("hello");
h_s.print();
// to make it work we need a &&str or a &String
let s = "hello"; // &'static str
let h_s = &s; // & &str
h_s.print(); // now self is a &str
Eh... this is awkward... Luckily we have a way to generalize the struct to work directly with str (and unsized types in general): ?Sized
//same as before, only added the ?Sized bound
struct Foo<'a, T: ?Sized>(&'a T)
where
T: 'a;
impl<'a, T: ?Sized> Print for Foo<'a, T>
where
T: 'a + fmt::Display,
{
fn print(&self) {
println!("{}", self.0)
}
}
now this works:
let h = Foo("hello");
h.print();
playground
For a less contrived (but simple) actual example, you can look at the Borrow trait in the standard library.
Back to your question
trait Foo for ?Sized {
fn foo(&self) -> i32;
}
the for ?Sized syntax is now obsolete. It used to refer to the type of Self, declaring that `Foo can be implemented by an unsized type, but this is now the default. Any trait can now be implemented for an unsized type, i.e. you can now have:
trait Foo {
fn foo(&self) -> i32;
}
//[i32] is unsized, but the compiler does not complain for this impl
impl Foo for [i32] {
fn foo(&self) -> i32 {
5
}
}
If you don't want your trait to be implementable for unsized types, you can use the Sized bound:
// now the impl Foo for [i32] is illegal
trait Foo: Sized {
fn foo(&self) -> i32;
}
To amend the example that Paolo Falabella has given, here is a different way of looking at it with the use of a property.
struct Foo<'a, T>
where
T: 'a + ?Sized,
{
printable_object: &'a T,
}
impl<'a, T> Print for Foo<'a, T>
where
T: 'a + ?Sized + fmt::Display,
{
fn print(&self) {
println!("{}", self.printable_object);
}
}
fn main() {
let h = Foo {
printable_object: "hello",
};
h.print();
}
At the moment, to create a HasFoo storing a type-erased Foo you need to first create one with a fixed concrete type and then coerce a pointer to it to the DST form, that is
let has_too: &HasFoo<Foo> = &HasFoo { f: Bar };
Calling has_foo.f.foo() then does what you expect.
In future these DST casts will almost certainly be possible with as, but for the moment coercion via an explicit type hint is required.
Here is a complete example based on huon's answer. The important trick is to make the type that you want to contain the DST a generic type where the generic need not be sized (via ?Sized). You can then construct a concrete value using Bar1 or Bar2 and then immediately convert it.
struct HasFoo<F: ?Sized = dyn Foo>(F);
impl HasFoo<dyn Foo> {
fn use_it(&self) {
println!("{}", self.0.foo())
}
}
fn main() {
// Could likewise use `&HasFoo` or `Rc<HasFoo>`, etc.
let ex1: Box<HasFoo> = Box::new(HasFoo(Bar1));
let ex2: Box<HasFoo> = Box::new(HasFoo(Bar2));
ex1.use_it();
ex2.use_it();
}
trait Foo {
fn foo(&self) -> u32;
}
struct Bar1;
impl Foo for Bar1 {
fn foo(&self) -> u32 {
9
}
}
struct Bar2;
impl Foo for Bar2 {
fn foo(&self) -> u32 {
10
}
}

Resources