I have a trait Foo. This has a method which takes a generic type implementing Bar and is therefore not object safe:
trait Bar {}
trait Foo {
fn foofunc<B: Bar>(&self, b: B);
}
I want to make the trait Foo object safe. I gather the usual way to do this is to wrap it in a new, object-safe, trait (see here). Something along the lines of:
trait FooObjectSafe<B>
where B: Bar,
{
fn foofunc(&self, b: B);
}
impl<B, F> FooObjectSafe<B> for F
where B: Bar,
F: Foo,
{
fn foofunc(&self, b: B) {
Foo::foofunc(self, b)
}
}
This seems very limiting however. If there is a function use_foo which takes a generic type implementing Foo, then it cannot be used with FooObjectSafe without changing its signature (I don't want to do this as in practise these functions come from different modules and are very divorced from one another):
struct BarImpl;
impl Bar for BarImpl {}
struct FooImpl;
impl Foo for FooImpl {
fn foofunc<B: Bar>(&self, b: B) {}
}
fn main() {
let foos = [
Box::new(FooImpl{}) as Box<dyn FooObjectSafe<BarImpl>>,
Box::new(FooImpl{})
];
use_foo(foos[0]);
}
results in the error
error[E0277]: the trait bound `Box<dyn FooObjectSafe<BarImpl>>: Foo` is not satisfied
--> src/main.rs:43:13
|
43 | use_foo(foos[0]);
| ------- ^^^^^^^ the trait `Foo` is not implemented for `Box<dyn FooObjectSafe<BarImpl>>`
| |
| required by a bound introduced by this call
|
= help: the trait `Foo` is implemented for `FooImpl`
note: required by a bound in `use_foo`
--> src/main.rs:9:14
|
8 | fn use_foo<F>(foo: F)
| ------- required by a bound in this
9 | where F: Foo,
| ^^^ required by this bound in `use_foo`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error
Is there a better way to do this? I suspect I'm making some architectural faux pas here, but what exactly?
Playground
Related
Compilation of this snippet:
trait Base {
type T;
fn get_p(&self) -> &Self::T;
}
trait OnBase: Base {
fn get_a(&self) -> &A;
}
impl<S, T> OnBase for S
where
S: Base<T = dyn OnBase<T = T>>,
{
fn get_a(&self) -> &A {
self.get_p().get_a()
}
}
struct A {}
Fails with:
error[E0311]: the parameter type `T` may not live long enough
--> src/blanket_with_ref.rs:17:9
|
17 | self.get_p().get_a()
| ^^^^^^^^^^^^
|
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
--> src/blanket_with_ref.rs:16:14
|
16 | fn get_a(&self) -> &A {
| ^^^^^
note: ...so that the type `T` will meet its required lifetime bounds
--> src/blanket_with_ref.rs:17:9
|
17 | self.get_p().get_a()
| ^^^^^^^^^^^^
help: consider adding an explicit lifetime bound...
|
14 | impl <S, T: 'a> OnBase for S where S:Base<T=dyn OnBase<T=T>> {
| ++++
I vaguely comprehend that I must somehow tell it that lifetimes of Base and OnBase should be same but even if I add 'a to all traits and refrences it keeps failing.
Is it possible to somehow make it compile?
P.S. - it works if get_a returns plain A.
pps - in the real app it should be a kind of a strategy delegating to whatever impl it encapsulates
playground
This is probably what you actually want, instead of T = dyn OnBase<T = T>:
trait Base {
type T;
fn get_p(&self) -> &Self::T;
}
trait OnBase: Base {
fn get_a(&self) -> &A;
}
impl<S> OnBase for S
where
S: Base,
<S as Base>::T: OnBase,
{
fn get_a(&self) -> &A {
self.get_p().get_a()
}
}
struct A;
I'm not sure what purpose OnBase: Base serves, though. If OnBase is already Base, then why do any of this? And what should it return in get_p? With the current layout, it's really easy to get caught up in an infinite get_a recursion.
I'm trying to implement a trait that has a supertrait, like so:
trait A {
fn do_a(&self);
}
trait B: A {
fn do_b(&self);
}
struct S {}
impl B for S {
fn do_a(&self) {}
fn do_b(&self) {}
}
When I run cargo build I get these compiler errors:
error[E0407]: method `do_a` is not a member of trait `B`
--> src/example.rs:12:5
|
12 | fn do_a(&self) {}
| ^^^^^^^^^^^^^^^^^ not a member of trait `B`
error[E0277]: the trait bound `example::S: example::A` is not satisfied
--> src/example.rs:11:6
|
5 | trait B: A {
| - required by this bound in `example::B`
...
11 | impl B for S {
| ^ the trait `example::A` is not implemented for `example::S`
I keep re-reading about supertraits, but I'm having trouble understanding this error.
The first error seems to contradict what trait B: A is telling the program to do.
The second error seems to contradict that the implementation of do_a(&self) {} satisfies A.
What am I missing here? Is my mental model wrong, or is my code missing some necessary boilerplate, or both?
I believe that the syntax is more about bounding the type (e.g. a type T that implements B must necessarily implement A) than inheritance in the object-oriented sense. If you write out the impls separately it compiles fine:
trait A {
fn do_a(&self);
}
trait B: A {
fn do_b(&self);
}
struct S {}
impl A for S {
fn do_a(&self) {}
}
impl B for S {
fn do_b(&self) {}
}
Playground
N.B. that if you remove the impl for A the code no longer compiles, the constraint that an impl of B must also impl A is no longer satisfied.
This is actually an offshoot of this SO question.
Consider the following code:
trait Trait<'b> {
fn func(&'b self) {}
}
struct Struct {}
impl<'s> Trait<'s> for Struct {}
fn test<'s, T:'s>(t: T)
where
T: Trait<'s>,
{
t.func();
}
It fails, as the compiler sees that t lives for less than the 's and 's is set by the caller (i.e longer than the stack-frame of the func) and traits are invariant over type parameters. However, if I introduce HRTB (Higher Rank Trait Bounds) here, the code compiles:
fn test<T>(t: T)
where
T: for<'s> Trait<'s>,
{
t.func();
}
Now, the trait Trait<'s> is implemented for all possible lifetimes 's represents and accordingly the right one gets picked by the compiler.
But then why the following code fails ?
struct Temp<'a> {
x: &'a i32,
}
fn test<T>(t: T)
where
for<'s> T: 's,
{
}
fn main() {
let d = 1i32;
test(Temp { x: &d });
}
It gives the error:
error[E0597]: `d` does not live long enough
--> src/main.rs:13:20
|
13 | test(Temp { x: &d });
| ---------------^^---
| | |
| | borrowed value does not live long enough
| argument requires that `d` is borrowed for `'static`
14 | }
| - `d` dropped here while still borrowed
What is the difference here? Conceptually, I found the earlier example same as this one. Why it is expected that the concrete type T should only be/contain reference(s) with 'static lifetime(s) ?
I'm trying to define a trait with a function that returns an associated type with the same lifetime as one parameter.
Conceptually something like the following (which doesn't work: lifetime parameter not allowed on this type [Self::Output]):
trait Trait {
type Output;
fn get_output<'a>(&self, input: &'a i32) -> Self::Output<'a>;
}
I found several questions about lifetimes for associated types on Stack Overflow and the Internet, but none seem to help. Some suggested defining the lifetime on the whole trait:
trait Trait<'a> {
type Output;
fn get_output(&self, input: &'a i32) -> Self::Output;
}
but this doesn't work either: it compiles, but then the following function fails to compile:
fn f<'a, T>(var: &T)
where T: Trait<'a>
{
let input = 0i32;
let output = var.get_output(&input);
}
giving an error:
error: `input` does not live long enough
--> <anon>:9:35
|
| let output = var.get_output( &input );
| ^^^^^ does not live long enough
| }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the body at 7:48...
--> <anon>:7:49
|
| fn f<'a, T>( var : &T ) where T : Trait<'a> {
| _________________________________________________^ starting here...
| | let input = 0i32;
| | let output = var.get_output( &input );
| | }
| |_^ ...ending here
How should I define the trait so that it behaves the way I want?
This is currently impossible, even in nightly Rust.
This requires some form of Higher Kinded Types (HKT), and the current approach envisaged is dubbed Associated Type Constructor (ATC).
The main motivation for introducing ATC is actually this very usecase.
With ATC, the syntax would be:
trait Trait {
type Output<'a>;
fn get_output<'a>(&self, input: &'a i32) -> Self::Output<'a>;
}
Note: if you wish to learn about ATCs, see Niko's series of articles.
For the particular example you have, you can work around this with HRTB (Higher Ranked Traits Bounds) as noted by Shepmaster:
fn f<T>(var: &T)
where for<'a> T: Trait<'a>
{ ... }
however this is fairly limited (notably, limited to trait bounds).
This requires using higher-ranked trait bounds:
fn f<T>(var: &T)
where for<'a> T: Trait<'a>
{
let input = 0i32;
let output = var.get_output(&input);
}
See also:
How does for<> syntax differ from a regular lifetime bound?
Suppose I want to create some type that wraps some other generic type, like so:
struct MyWrapper<T> {
pub inner: T,
}
Now I want my type to have a method if the inner type satisfies a specific bound. For example: I want to print it (in this example without using fmt traits for simplicity). To do this I have two possibilities: adding a bound to the impl or to the method itself.
Method Bound
impl<T> MyWrapper<T> {
pub fn print_inner(&self) where T: std::fmt::Display {
println!("[[ {} ]]", self.inner);
}
}
When calling this function with a MyWrapper<()> I get:
error[E0277]: `()` doesn't implement `std::fmt::Display`
--> src/main.rs:20:7
|
20 | w.print_inner();
| ^^^^^^^^^^^ `()` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
|
= help: the trait `std::fmt::Display` is not implemented for `()`
Impl Bound
impl<T: std::fmt::Display> MyWrapper<T> {
pub fn print_inner(&self) {
println!("[[ {} ]]", self.inner);
}
}
Calling it incorrectly again, gives:
error[E0599]: no method named `print_inner` found for type `MyWrapper<()>` in the current scope
--> src/main.rs:19:7
|
1 | struct MyWrapper<T> {
| ------------------- method `print_inner` not found for this
...
19 | w.print_inner();
| ^^^^^^^^^^^
|
= note: the method `print_inner` exists but the following trait bounds were not satisfied:
`() : std::fmt::Display`
My question is: what is more idiomatic? Are there semantic differences (aside from lifetime stuff with traits, explained here)? Are there differences apart from the compiler message?
One semantic difference is that with the type bound on the method you can partially implement a trait:
trait Trait {
fn f(self) where Self: std::fmt::Display;
fn g(self);
}
struct Struct<T>(T);
impl<T> Trait for Struct<T> {
fn f(self) where Struct<T>: std::fmt::Display {
println!("{}", self);
}
fn g(self) {
println!("Hello world!");
}
}
fn main() {
let s = Struct(vec![1]);
// f is not implemented, but g is
//s.f();
s.g();
}
This may be useful if you have many optional methods with different type bounds, which would otherwise require separate traits.