How to specify generics that can be dereferenced into a trait - rust

I have structs A and B, where B can be dereferenced into A.
A implements GetValue with the function .get_value(), and therefore B also indirectly implements GetValue.
Now I'd like to write a function print_value that can accept &A and &B, so it can internally call .get_value() on them. Technically this should be possible, because both of them can be dereferenced into &GetValue; &A by dereferencing once, and &B by dereferencing twice.
The question is: How do I specify the generic of print_value to achieve this?
Here is my attempt:
use std::ops::Deref;
//### external library code ######################
struct A(i32);
struct B(A);
impl Deref for B {
type Target = A;
fn deref(&self) -> &Self::Target {
&self.0
}
}
trait GetValue {
fn get_value(&self) -> i32;
}
impl GetValue for A {
fn get_value(&self) -> i32 {
self.0
}
}
//### my code ####################################
fn print_value<T: Deref>(val: T)
where
<T as Deref>::Target: GetValue,
{
println!("{}", val.get_value())
}
fn main() {
let a = A(1);
let b = B(A(2));
println!("{}", a.get_value());
println!("{}", b.get_value());
print_value(&a);
print_value(&b); // < fails with error "the trait bound `B: GetValue` is not satisfied"
}
The problem here is that <T as Deref>::Target: GetValue does not match &B, because &B would have to be dereferenced twice. The compiler automatically dereferences many times when a function is called, so is there a way to achieve the same through generics?
Note
I only have power over the implementation of print_value. I do not have the power over the other functions.
A more real-life example would be:
get_value = get_error_source
A = an error type
B = Box<dyn A>
GetValue = std::error::Error
I just wanted to keep it as abstract as possible to avoid confusion.
I'm still quite certain that this is not an XY problem.

Instead of making a function have an overly complicated signature just to signify that it can take anything that you know to get_value of, you could do a blanket implementation. This way, you automatically signify that something you can get_value of, well, you can get_value of.
impl<T> GetValue for T
where
T: Deref,
<T as Deref>::Target: GetValue,
{
fn get_value(&self) -> i32 {
self.deref().get_value()
}
}
Just adding that makes it work, see the playground.

You just need to actually call deref on the object, then you would pass a B or an &A :
use std::ops::Deref;
...
fn print_value<T: Deref>(val: T)
where
<T as Deref>::Target: GetValue,
{
println!("{}", val.deref().get_value())
}
fn main() {
let a = A(1);
let b = B(A(2));
println!("{}", a.get_value());
println!("{}", b.get_value());
print_value(&a);
print_value(b);
}
Playground
Outputs:
1
2
1
2

Related

Rust - implementing trait for Deref: the parameter type `T` may not live long enough

I have a trait:
trait Foo {
fn bar(&self) -> Cow<str>;
}
And I want to implement it for any type that implements Deref with a target of a type that implements Foo. Basically:
impl<T: Foo, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(std::ops::Deref::deref(self))
}
}
Unfortunately, this gives the error the parameter type T may not live long enough.
My understanding is that T could have a reference within it that has a short lifetime, and the lifetime bound of the return value of Cow<str> is linked to the lifetime of &self due to lifetime elision, which would cause problems.
I'm not sure how I can fix this, since I'm not able to bound any of the lifetimes in bar. I can try to make sure T lives as long as &self, but this doesn't work.
impl<'a, T: Foo + 'a, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&'a self) -> Cow<'a, str> {
<T as Foo>::bar(std::ops::Deref::deref(self))
}
}
I get the error method not compatible with trait since the lifetimes don't match the trait defenition anymore. I've tried all sorts of different ways of adding lifetime bounds and I always get one of those two errors.
I am able to implement Foo for a specific type that implements Deref:
impl<T: Foo> Foo for Box<T> {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(self)
}
}
I'm not sure why that works but the original example doesn't.
The Box version works because of the deref coercion the compiler will do when it sees a reference and expects a different reference.
You can use the same mechanic when using a generic implementor of Deref to ensure that it Derefs to an owned type you can simply add a 'static lifetime bound on T like this:
impl<T: Foo + 'static, D: std::ops::Deref<Target = T>> Foo for D {
fn bar(&self) -> Cow<str> {
<T as Foo>::bar(self)
}
}
playground
Note: there is rarely a need to call methods of std::ops traits directly, they're all just the methods behind Rusts operators, deref for example is the method behind unary *
Update:
Since there is an additional requirement that T might not be static we have to thread through the lifetime like you tried in your second example, like the error you're getting suggest you have to adjust the trait to take a lifetime as well:
use std::borrow::Cow;
trait Foo<'a> {
fn bar(&self) -> Cow<'a, str>;
}
impl<'a, T: Foo<'a>, D: std::ops::Deref<Target = T>> Foo<'a> for D {
fn bar(&self) -> Cow<'a, str> {
<T as Foo>::bar(self)
}
}
struct S<'a> {
val: &'a str,
}
impl<'a> Foo<'a> for S<'a> {
fn bar(&self) -> Cow<'a, str> {
todo!()
}
}
fn main() {
let val = String::from("test");
let s = S { val: &val }; // error: `val` does not live long enough
let b = Box::new(s);
let cow = Foo::bar(&b); // argument requires that `val` is borrowed for `'static`
}

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)
}
}

Why Rust can't coerce mutable reference to immutable reference in a type constructor?

It is possible to coerce &mut T into &T but it doesn't work if the type mismatch happens within a type constructor.
playground
use ndarray::*; // 0.13.0
fn print(a: &ArrayView1<i32>) {
println!("{:?}", a);
}
pub fn test() {
let mut x = array![1i32, 2, 3];
print(&x.view_mut());
}
For the above code I get following error:
|
9 | print(&x.view_mut());
| ^^^^^^^^^^^^^ types differ in mutability
|
= note: expected reference `&ndarray::ArrayBase<ndarray::ViewRepr<&i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
found reference `&ndarray::ArrayBase<ndarray::ViewRepr<&mut i32>, ndarray::dimension::dim::Dim<[usize; 1]>>`
It is safe to coerce &mut i32 to &i32 so why it is not applied in this situation? Could you provide some examples on how could it possibly backfire?
In general, it's not safe to coerce Type<&mut T> into Type<&T>.
For example, consider this wrapper type, which is implemented without any unsafe code and is therefore sound:
#[derive(Copy, Clone)]
struct Wrapper<T>(T);
impl<T: Deref> Deref for Wrapper<T> {
type Target = T::Target;
fn deref(&self) -> &T::Target { &self.0 }
}
impl<T: DerefMut> DerefMut for Wrapper<T> {
fn deref_mut(&mut self) -> &mut T::Target { &mut self.0 }
}
This type has the property that &Wrapper<&T> automatically dereferences to &T, and &mut Wrapper<&mut T> automatically dereferences to &mut T. In addition, Wrapper<T> is copyable if T is.
Assume that there exists a function that can take a &Wrapper<&mut T> and coerce it into a &Wrapper<&T>:
fn downgrade_wrapper_ref<'a, 'b, T: ?Sized>(w: &'a Wrapper<&'b mut T>) -> &'a Wrapper<&'b T> {
unsafe {
// the internals of this function is not important
}
}
By using this function, it is possible to get a mutable and immutable reference to the same value at the same time:
fn main() {
let mut value: i32 = 0;
let mut x: Wrapper<&mut i32> = Wrapper(&mut value);
let x_ref: &Wrapper<&mut i32> = &x;
let y_ref: &Wrapper<&i32> = downgrade_wrapper_ref(x_ref);
let y: Wrapper<&i32> = *y_ref;
let a: &mut i32 = &mut *x;
let b: &i32 = &*y;
// these two lines will print the same addresses
// meaning the references point to the same value!
println!("a = {:p}", a as &mut i32); // "a = 0x7ffe56ca6ba4"
println!("b = {:p}", b as &i32); // "b = 0x7ffe56ca6ba4"
}
Full playground example
This is not allowed in Rust, leads to undefined behavior and means that the function downgrade_wrapper_ref is unsound in this case. There may be other specific cases where you, as the programmer, can guarantee that this won't happen, but it still requires you to implement it specifically for those case, using unsafe code, to ensure that you take the responsibility of making those guarantees.
Consider this check for an empty string that relies on content staying unchanged for the runtime of the is_empty function (for illustration purposes only, don't use this in production code):
struct Container<T> {
content: T
}
impl<T> Container<T> {
fn new(content: T) -> Self
{
Self { content }
}
}
impl<'a> Container<&'a String> {
fn is_empty(&self, s: &str) -> bool
{
let str = format!("{}{}", self.content, s);
&str == s
}
}
fn main() {
let mut foo : String = "foo".to_owned();
let container : Container<&mut String> = Container::new(&mut foo);
std::thread::spawn(|| {
container.content.replace_range(1..2, "");
});
println!("an empty str is actually empty: {}", container.is_empty(""))
}
(Playground)
This code does not compile since &mut String does not coerce into &String. If it did, however, it would be possible that the newly created thread changed the content after the format! call but before the equal comparison in the is_empty function, thereby invalidating the assumption that the container's content was immutable, which is required for the empty check.
It seems type coercions don't apply to array elements when array is the function parameter type.
playground

How can I write a method to wrap any value in my type that can be called multiple times without requiring type annotations?

I wrote a type Wrapper<T> which contains a value of T:
struct Wrapper<T>(T);
I want a method to_wrap which would allow me to write code like this, where b is Wrapper<i32> and c is Wrapper<i32>:
let a = 12i32;
let b = a.to_wrap();
let c = b.to_wrap();
I want v.to_wrap() to always produce a Wrapper<T> where T is NOT a Wrapper. If v is a Wrapper<T>, v.to_wrap() will also be a Wrapper<T> with the same value.
The code I wrote closest to my idea is:
#![feature(specialization)]
#[derive(Debug)]
struct Wrapper<T>(T);
trait ToWrapper<W> {
fn to_wrap(self) -> W;
}
impl<T> ToWrapper<Wrapper<T>> for T {
default fn to_wrap(self) -> Wrapper<T> {
Wrapper(self)
}
}
impl<T> ToWrapper<Wrapper<T>> for Wrapper<T> {
fn to_wrap(self) -> Self {
self
}
}
fn main() {
let a = 1i32;
println!("{:?}", a);
let a = 1.to_wrap();
println!("{:?}", a);
let a: Wrapper<i32> = 1.to_wrap().to_wrap();
// let a = 1.to_wrap().to_wrap();
// boom with `cannot infer type`
println!("{:?}", a);
}
Playground
This has a compilation error if I erase the type annotation on from let a: Wrapper<i32> = 1.to_wrap().to_wrap():
error[E0282]: type annotations needed
--> src/main.rs:27:9
|
27 | let a = 1.to_wrap().to_wrap();
| ^
| |
| cannot infer type
| consider giving `a` a type
I want the Rust compiler to automatically derive the type of 1.to_wrap().to_wrap(). How can I write the correct version, or why is it not possible to write it?
I do not believe you can accomplish your goal of implementing a single trait using specialization at this point in time.
Your trait definition allows for multiple implementations of the trait for the same type:
trait ToWrapper<W> {
fn to_wrap(self) -> W;
}
impl ToWrapper<i32> for u8 {
fn to_wrap(self) -> i32 {
i32::from(self)
}
}
impl ToWrapper<i16> for u8 {
fn to_wrap(self) -> i16 {
i16::from(self)
}
}
With such a setup, it's impossible to know what the resulting type of to_wrap should be; you will always need to provide the output type somehow. Then you compound the problems by attempting to call to_wrap on an unknown type that will produce another unknown type!
Normally, using associated types would be the solution, but you cannot switch to those here because of how they interact with specialization.
See also:
When is it appropriate to use an associated type versus a generic type?
Mismatch between associated type and type parameter only when impl is marked `default`
How do I unwrap an arbitrary number of nested Option types?
You can achieve something like this on nightly, not using specialization, but using two different traits and an auto trait to distinguish between them.
#![feature(auto_traits)]
#![feature(negative_impls)]
auto trait IsWrap {}
#[derive(Debug)]
struct Wrapper<T>(T);
impl<T> !IsWrap for Wrapper<T> {}
trait ToWrapper: Sized {
fn to_wrap(self) -> Wrapper<Self>;
}
impl<T: IsWrap> ToWrapper for T {
fn to_wrap(self) -> Wrapper<T> {
Wrapper(self)
}
}
trait ToWrapperSelf {
fn to_wrap(self) -> Self;
}
impl<T> ToWrapperSelf for Wrapper<T> {
fn to_wrap(self) -> Self {
self
}
}
fn main() {
let a = 1.to_wrap();
println!("{:?}", a);
let a = 1.to_wrap().to_wrap();
println!("{:?}", a);
}
As with chabapok's suggestion, you can't use this technique to write a generic function that behaves one way when given one type and another way with another type (although see the links below). But you can use it when the concrete type is known to the compiler but not to the programmer -- macros come to mind as a possible use case.
It has one further advantage in that there is no possible ambiguity over which to_wrap method will be called on any type. Every type has at most one to_wrap method, since Wrappers only have ToWrapperSelf::is_wrap and non-Wrappers only have ToWrapper::is_wrap.
One other disadvantage is that !IsWrap for Wrapper<T> is "infectious": any type that contains or might contain a Wrapper<T> will also be automatically !IsWrap. If you call .to_wrap() on such a type, the compiler will not be able to find the method and will issue an error. If this is a problem, you can manually implement IsWrap for these types, but it might be more prudent to look for another, less fragile solution.
(The only exception to the above is Box<Wrapper<T>>: you can call ToWrapperSelf::to_wrap on it to get a Wrapper<T>. This happens due to the autodereferencing rules and because Box is special.)
See also
What is an auto trait in Rust?
The solution outlined above is similar to this answer.
Can I avoid eager ambiguity resolution for trait implementations with generics? has a similar "specialization but not really" flavor. My answer to that question can be combined with this answer to create traits and generic functions that dispatch Wrappers and non-Wrappers transparently, even though you can't leverage the full power of specialization.
#[derive(Debug)]
struct Wrapper<T>(T);
trait ToWrapper<W> {
fn to_wrap(self) -> Wrapper<W>;
}
impl<T> ToWrapper<T> for T {
fn to_wrap(self) -> Wrapper<T> {
Wrapper(self)
}
}
impl<T> Wrapper<T> {
fn to_wrap(self) -> Wrapper<T> {
self
}
}
fn main() {
let a = 1i32;
println!("{:?}", a);
let a = 1.to_wrap();
println!("{:?}", a);
let a: Wrapper<i32> = 1.to_wrap().to_wrap();
let b = 1.to_wrap().to_wrap();
println!("{:?}", a);
println!("{:?}", b);
}

From trait called inside a generic function

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.

Resources