Sorting out different lifetimes on Self and a method - rust

I posted a similar question (Rust lifetime error expected concrete lifetime but found bound lifetime) last night, but still can't figure out how to apply it to this case now. Once again, a simplified example bellow:
struct Ref;
struct Container<'a> {
r : &'a Ref
}
struct ContainerB<'a> {
c : Container<'a>
}
trait ToC {
fn from_c<'a>(r : &'a Ref, c : Container<'a>) -> Self;
}
impl<'b> ToC for ContainerB<'b> {
fn from_c<'a>(r : &'a Ref, c : Container<'a>) -> ContainerB<'a> {
ContainerB{c:c}
}
}
With the error message:
test.rs:16:3: 18:4 error: method `from_c` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter 'a
test.rs:16 fn from_c<'a>(r : &'a Ref, c : Container<'a>) -> ContainerB<'a> {
test.rs:17 ContainerB{c:c}
test.rs:18 }
test.rs:16:67: 18:4 note: expected concrete lifetime is the lifetime 'b as defined on the block at 16:66
test.rs:16 fn from_c<'a>(r : &'a Ref, c : Container<'a>) -> ContainerB<'a> {
test.rs:17 ContainerB{c:c}
test.rs:18 }
error: aborting due to previous error
What I think needs to happen is I need some way to equate / sub-type lifetime 'a, and lifetime 'b. Unlike the previous example there is no &self to use. I am guessing I can do this by adding a lifetime type argument to my trait(trait ToC<'a> ...), but I would prefer not to do this as it adds extra <'a> everywhere I want to use the trait as a type bound.
If anybody is curious(AKA can ignore this) where this might actually come up, I am using it in a library to convert between rust and python types. The trait is here. Everything works fine, but I am trying to implement a wrapper around the PyObject type (such as a numpy ndarray) and be able to convert it to and from a PyObject with this.
Thanks again!

This boils down to much the same problem as in your previous question.
Self refers to the type you are implementing the trait for. In this case it is ContainerB<'b>, and so the whole thing about its not being the same applies; this time this time there is nothing to tie 'b and 'a together, either; the lifetimes are and must be assumed by the compiler to be potentially disjoint. (This is as distinct to the &'a ContainerB<'b> which guaranteed 'b ≥ 'a.)
Once you are using a lifetime defined on the method, tying that in with a lifetime on Self is not possible. The solution that is probably best is to shift the lifetime parameter from the method onto the trait:
trait ToC<'a> {
fn from_c(r: &'a Ref, c: Container<'a>) -> Self;
}
impl<'a> ToC<'a> for ContainerB<'a> {
fn from_c(r: &'a Ref, c: Container<'a>) -> ContainerB<'a> {
ContainerB { c: c }
}
}

Related

Cannot use the associated type of a trait with uninferred generic parameters?

This example is from rust's error-index, whose explanation I still can't understand why this is the case
#![allow(unused)]
fn main() {
pub trait Foo<T> {
type A;
fn get(&self, t: T) -> Self::A;
}
fn foo2<I: for<'x> Foo<&'x isize>>(field: I::A) {} // error!
}
I does not implement Foo once in foo2(). It implements it multiple times, once for each lifetime of 'x.
Because of that, there is also not a single value for <I as Foo>::A. There are multiple, one for each instantiation of 'x.
When you want to specify I::A, you need to tell the compiler which I::A - that is, which lifetime to bind 'x with.

Inconsistency of lifetime bound requirement when storing closures

When I try to store closures to a HashMap, I come across a lifetime bound requirement reported by the compiler. It seems like an inconsistent requirement.
struct NoBox<C: Fn() -> ()>(HashMap<String, C>);
impl<C> NoBox<C>
where
C: Fn() -> (),
{
fn new() -> NoBox<C> {
NoBox(HashMap::new())
}
fn add(&mut self, str: &str, closure: C) {
self.0.insert(str.to_string(), closure);
}
}
This is Ok. The compiler is happy with it. However, when I try to wrap the closure into a trait object and store it. The compiler imposes a 'static lifetime bound on it.
struct Boxed(HashMap<String, Box<dyn Fn() -> ()>>);
impl Boxed {
fn new() -> Boxed {
Boxed(HashMap::new())
}
fn add<C>(&mut self, str: &str, closure: C)
where
C: Fn() -> ()//add 'static here fix the error
{
self.0.insert(str.to_string(), Box::new(closure)); //error: type parameter C may not live long enough, consider adding 'static lifebound
}
}
According to the complain of the compiler, C may not live long enough. It makes sense to add a 'static bound to it.
But, why the first case without boxing doesn't have this requirement?
To my understanding, if C contains some reference to an early-dropped referent, then store it in NoBox would also cause the invalid-reference problem. For me, it seems like an inconsistency.
NoBox is not a problem because if the function contains a reference to the lifetime, the type will stay contain this lifetime because the function type needs to be specified explicitly.
For example, suppose we're storing a closure that captures something with lifetime 'a. Then the closure's struct will looks like (this is not how the compiler actually desugars closures but is enough for the example):
struct Closure<'a> {
captured: &'a i32,
}
And when specifying it in NoBox, the type will be NoBox<Closure<'a>>, and so we know it cannot outlive 'a. Note this type may never be actually explicitly specified - especially with closures - but the compiler's inferred type still have the lifetime in it.
With Boxed on the other hand, we erase this information, and thus may accidentally outlive 'a - because it does not appear on the type. So the compiler enforces it to be 'static, unless you explicitly specify otherwise:
struct Boxed<'a>(HashMap<String, Box<dyn Fn() + 'a>>);

How to infer an appropriate lifetime for an implementation using lifetimes for structs and impl?

How do I resolve this error? What exactly am I telling the compiler when I use the "anonymous lifetime" in impl?
struct LineHandlerInfo<'a> {
label: &'a str,
match_literal: &'a str,
f: fn(&str) -> Option<&str>,
}
struct Game<'a> {
handlers: Vec<LineHandlerInfo<'a>>,
}
impl Game<'_> {
fn match_str<'a>(
&'a mut self,
label: &'a str,
match_literal: &'a str,
mut f: fn(&str) -> Option<&str>,
) {
let mut lh = LineHandlerInfo {
label,
match_literal,
f,
};
self.handlers.push(lh);
}
}
fn main() {
let mut g = Game {
handlers: Vec::new(),
};
g.match_str("echo hello", "hello", |s| {
println!("{}", s);
None
});
}
When I attempt to compile, I get the following error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:18:22
|
18 | let mut lh = LineHandlerInfo {
| ^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the method body at 12:18...
--> src/main.rs:12:18
|
12 | fn match_str<'a>(
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:19:13
|
19 | label,
| ^^^^^
note: but, the lifetime must be valid for the lifetime '_ as defined on the impl at 11:11...
--> src/main.rs:11:11
|
11 | impl Game<'_> {
| ^^
= note: ...so that the expression is assignable:
expected LineHandlerInfo<'_>
found LineHandlerInfo<'_>
How do I resolve this error and what exactly am I telling the compiler when I specify a lifetime on impl Game when I already have a lifetime on the struct?
How do I resolve this error and what exactly am I telling the compiler when I specify a lifetime on impl Game when I already have a lifetime on the struct?
I suspect your confusion stems from an incomplete understanding of the way in which lifetimes are declared and used in Rust.
Struct Lifetimes
In order to use a lifetime on a struct, you declare the lifetime inside the <> adjacent to the name of the struct you are declaring, and then refer to that lifetime inside the struct definition. Importantly, note that the lifetime declared there is scoped to the struct definition - it has no meaning outside.
For example (using the MRE that #Shepmaster provided):
struct Game<'a> {
handlers: Vec<&'a str>,
}
The struct Game contains a vector of references to strings, and the strings which are referenced must last at least as long as the Game struct.
Impl Lifetimes
When using a lifetime specifier on an impl block, you declare the lifetime inside the <> adjacent to the impl keyword, after which you may refer to the lifetime both in the struct being implemented, and inside the implementation itself, like this:
impl<'b> Game<'b> {
fn match_str(&mut self, label: &'b str) {
self.handlers.push(label);
}
}
Note that I am using an entirely different lifetime name here ('b) to illustrate that the the lifetime declaration on the struct is independent of the one on the impl block.
Breaking this down:
impl<'b>
This means that we are defining an implementation for a struct, and within that definition we will use the lifetime 'b
Game<'b> {
This means that the impl is for the struct Game with lifetime 'b - so any references to self inside this implementation are going to automatically have lifetime 'b as well.
fn match_str(&mut self, label: &'b str) {
Here we define the method match_str which takes an argument label. label is a string slice which also has the lifetime 'b - so it must last at least as long as the self that the method is called on.
In your original code, you had something like this:
impl Game<'_> {
fn match_str<'a>(&mut self, label: &'a str) {
...
}
}
This was telling the compiler:
That you are starting a new impl block that, and there are no lifetimes declared at impl level
That the implementation is for the struct Game; this struct has a lifetime parameter but we don't care about it and we are not going to tie it to any element of the implementation
We are defining a method match_str, and we are declaring a lifetime 'a which we can refer to in the rest of the function signature
We have an argument label which has the lifetime a, but we aren't relating this lifetime to anything else
More information:
Rust Book - Lifetime Annotations in Struct Definitions
Rust Book - Lifetime Annotations in Method Definitions
How do I resolve this error?
Remove the generic lifetime from the function, provide a name for the lifetime on the impl block instead of using the anonymous lifetime, then use the named lifetime in the function arguments. Remove the lifetime from &self:
impl<'a> Game<'a> {
fn match_str(&mut self, label: &'a str, match_literal: &'a str, f: fn(&str) -> Option<&str>) {
self.handlers.push(LineHandlerInfo {
label,
match_literal,
f,
});
}
}
See also:
Cannot borrow as mutable more than once at a time in one code - but can in another very similar
What exactly am I doing when I use the "anonymous lifetime" in impl?
You are effectively stating "I know there's a lifetime here, but I don't care about it". However, that's not true for your case; you do care about the lifetime that parameterizes the type because that's what your variables need to match.
See also:
'_, the anonymous lifetime in the Edition Guide
for a struct with a function pointer in it
This has nothing to do with function pointers. When encountering problems while programing, I recommend creating a minimal, reproducible example, stripping out things that don't make the error go away. This allows you to focus on exactly the problem at hand. For example, this reproduces the same error:
struct Game<'a> {
handlers: Vec<&'a str>,
}
impl Game<'_> {
fn match_str<'a>(&mut self, label: &'a str) {
self.handlers.push(label);
}
}

Why is this trait/implementation incompatible - bound lifetime vs concrete lifetime

I'm struggling with this error rustc gives me:
error: method `create_shader_explicit` has an incompatible type for trait: expected bound lifetime parameter 'a, found concrete lifetime
My trait declaration is pretty much this:
pub trait GraphicsContext<R: Resources> {
/// Creates a shader object
fn create_shader<'a>(&'a self, shader::Stage, source: &str) ->
Result<handle::Shader<R>, shader::CreateError>;
}
Here's my implementation,
pub struct OpenGLResources<'a> {
phantom: PhantomData<&'a u32>
}
impl<'a> Resources for OpenGLResources<'a> {
type Shader = Shader<'a>;
}
impl<'z> GraphicsContext<OpenGLResources<'z>> for OpenGLGraphicsContext {
/// Creates a shader object
fn create_shader<'a>(&'a self, stage: shader::Stage, source: &str) ->
Result<handle::Shader<OpenGLResources>, shader::CreateError> {
let shader = Shader::new(self, stage);
try!(shader.compile_from_source(source));
Ok(shader)
}
}
In other questions on StackOverflow, they are missing things like <'a> between create_shader and (), however when I compare the fn definitions in mine they look identical.
EDIT:
Changing the definition inside impl to the following fixes that issue
fn create_shader<'a>(&'a self, stage: shader::Stage, source: &str) ->
Result<handle::Shader<OpenGLResources**<'z>**>, shader::CreateError>
But then the issue is that 'a and 'z need to be the same lifetime. If I change it to this:
fn create_shader(**&'z** self, stage: shader::Stage, source: &str) ->
Result<handle::Shader<OpenGLResources<'z>>, shader::CreateError>
The impl block works, but then I need a way of specifying the 'z lifetime in the trait definition. I tried the following:
pub trait<'z> GraphicsContext<R: Resources<'z>>
But it didn't work.
When comparing things like this, you need to remember to expand all the generics so that you can actually compare it all. In this case, you haven’t expanded R. If you do, the answer becomes obvious: R is OpenGLResources<'z>, linking the OpenGLResources to the impl block, whereas your method definition has elided the lifetime on OpenGLResources, causing it to be inferred as self’s lifetime, which is 'a.
Thanks the hints of #Chris Morgan I managed to implement this functionality and its now working fine.
If we start with the base trait with the 'a lifetime included:
trait Resources<'a> {
type Shader: Shader;
type ShaderProgram: ShaderProgram;
}
Then implement it for OpenGL. (note the PhantomData struct)
struct OpenGLResources<'a> {
phantom: PhantomData<&'a u32> // 'a is the lifetime of the context reference
}
impl<'a> ResourcesTrait<'a> for Resources<'a> {
type Shader = Shader<'a>;
type ShaderProgram = ShaderProgram<'a>;
type CommandBuffer = CommandBuffer;
type CommandBufferBuilder = CommandBufferBuilder;
}
Its a bit verbose, but the GraphicsContext trait works fine too now. The 'a lifetime goes in the type parameters part.
trait GraphicsContext<'a, R: Resources<'a>> {
fn create_shader(&'a self, ty: Type, source: &str) -> Result<R::Shader, ShaderCreationError>
}
Finally this is the required code in the graphics context implementation.
It is extremely verbose with the 'a lifetimes sprinkled everywhere but at least it works!
impl<'a> GraphicsContext<'a, Resources<'a>> for OpenGLGraphicsContext

Why "explicit lifetime bound required" for Box<T> in struct?

Editor's note: This code no longer produces the same error after RFC 599 was implemented, but the concepts discussed in the answers are still valid.
I'm trying to compile this code:
trait A {
fn f(&self);
}
struct S {
a: Box<A>,
}
and I'm getting this error:
a.rs:6:13: 6:14 error: explicit lifetime bound required
a.rs:6 a: Box<A>,
I want S.a to own an instance of A, and don't see how that lifetime is appropriate here. What do I need to do to make the compiler happy?
My Rust version:
rustc --version
rustc 0.12.0-pre-nightly (79a5448f4 2014-09-13 20:36:02 +0000)
(Slightly pedantic point: that A is a trait, so S is not owning an instance of A, it is owning an boxed instance of some type that implements A.)
A trait object represents data with some unknown type, that is, the only thing known about the data is that it implements the trait A. Because the type is not known, the compiler cannot directly reason about the lifetime of the contained data, and so requires that this information is explicitly stated in the trait object type.
This is done via Trait+'lifetime. The easiest route is to just use 'static, that is, completely disallow storing data that can become invalid due to scopes:
a: Box<A + 'static>
Previously, (before the possibility of lifetime-bounded trait objects and this explicit lifetime bound required error message was introduced) all boxed trait objects were implicitly 'static, that is, this restricted form was the only choice.
The most flexible form is exposing the lifetime externally:
struct S<'x> {
a: Box<A + 'x>
}
This allows S to store a trait object of any type that implements A, possibly with some restrictions on the scopes in which the S is valid (i.e. for types for which 'x is less than 'static the S object will be trapped within some stack frame).
The problem here is that a trait can be implemented for references too, so if you don't specify the required lifetime for Box anything could be stored in there.
You can see about lifetime requirements in this rfc.
So one possible solution is to bind the lifetime so Send (we put I in S):
trait A {
fn f(&self);
}
struct I;
impl A for I {
fn f(&self) {
println!("A for I")
}
}
struct S {
a: Box<A + Send>
}
fn main() {
let s = S {
a: box I
};
s.a.f();
}
The other is setting the lifetime to 'a (we can put a reference &I or I to S):
trait A {
fn f(&self);
}
struct I;
impl A for I {
fn f(&self) {
println!("A for I")
}
}
impl <'a> A for &'a I {
fn f(&self) {
println!("A for &I")
}
}
struct S<'a> {
a: Box<A + 'a>
}
fn main() {
let s = S {
a: box &I
};
s.a.f();
}
Note that this is more general and we can store both references and owned data (Send kind that has a lifetime of 'static) but you require a lifetime parameter everywhere the type is used.

Resources