Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
This is a good summary of the situation. There's one more twist to it though; I not only want both ownership and aliasing, I also want send-ability. That is, it should be possible to send the whole arena to another task. I think this rules out option 1 (though I don't know enough about lifetimes to be sure). It leaves option 2 on the table, though. The main problem with option 2 is that if one borrows a mutable pointer to `root.poolOfSomeObjects[someIndex]` then the whole `root` is now considered to be borrowed-as-mutable, disallowing borrowing a mutable pointer to `root.poolOfOtherObjects[otherIndex]`. I'm tempted to say that the type system should be smart enough to allow this, but I'm not 100% certain it is actually safe to do so without some run-time support. For now I am going with (3) which is using an UnsafePtr struct and scary comments :-( On Fri, Oct 25, 2013 at 7:05 PM, Niko Matsakis n...@alum.mit.edu wrote: On Mon, Sep 30, 2013 at 08:10:45PM +0300, Oren Ben-Kiki wrote: That's good! But there remains the fact that there's no way to say my lifetime is the same as the struct that contains me. If 'self specialness goes away, perhaps it can be re-introduced to mean that (or a different name can be given to it). So, I have had this thread on a must read list of e-mails for a while, but didn't get around to it until just now. Sorry about that. It is true that there is no way to have a lifetime that means as long as the current struct -- at least not in a type definition. The reason for this is that this is not a well-defined thing; structs can be moved, for example. The only place you can get a lifetime like that is in a method: fn foo'a('a mut self, ...) Here, 'a is the lifetime you are looking for (the current lifetime of the struct itself). We do have a way to express the notion of memory that moves with a struct and is freed when the struct is freed: ownership. That's what a `~` pointer is for. But of course the `~` pointer is designed for recursive ownership and transfers and thus prevents aliasing, which may not be what you need. Sometimes you want ownership and aliasability: basically you want to be able to create a subcomponent tied to a struct that will never itself be moved out of the struct into some other container. You can imagine doing this by having an arena that moves with the struct, and pointers that live as long as that arena. I had originally hoped to support this (that was indeed the origin of the 'self name) but it's quite complex to do so; that lifetime is a kind of existential lifetime and we don't really have a good way to capture it. In the meantime, you have two options: 1. Parameterize the struct with a lifetime, and have it contain the arena that way. This technique works when there is ultimately some master stack frame that the struct will not outlive; this master frame owns the arena, and the struct just borrows it. You can see an example in this (yet to be landed) code. [1] 2. Have the struct own a vector or other data structure, and replace pointers with indices. This works best when the struct will be moved around. You can see an example in this Graph data structure. [2] While I know that neither technique feels perfect, they are quite workable, and I have used both with much rejoicing. Niko [1] https://gist.github.com/nikomatsakis/7157110 [2] https://github.com/mozilla/rust/blob/master/src/librustc/middle/graph.rs ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
Huh, this is _exactly_ my use case. I have data structures which I grow but never shrink, and I never move anything out of them. This idiom isn't that uncommon when writing in functional style... I incrementally build a complex structure that allows quick access to the same pieces using different criteria (e.g., access a piece by a unique id, or look it up by a path, or via a direct pointer held by a related piece, etc.). All accesses are of (possibly mutable) borrowed pointers that live as long as the whole thing exist. Then when done I can discard the whole thing. Sometimes I have a less-complex structure to which I attach a related view structure. The view holds borrowed pointers to pieces of the original immutable structure, allowing efficient access in new and interesting ways. When done I can then discard the view and keep the original. So basically, I want something that gives me the freedoms granted to 'static, but only for as long as the main structure provably exists. Something like 'shadow :-) I found Rust doesn't like these idioms at all. I some cases, where I was too tired, performance wasn't an issue, and there was no need to send the whole thing between tasks, I just used @ pointers. Otherwise, I used RcMut, though this incurs boilerplate access code and hurts performance for no real reason. In critical cases I may end up using unsafe pointers... Using a macro - hmm. Interesting and if possible, would be a great solution. I'm not certain what such a macro would expand to, though. It would need to be something that would express the concept of I live only as long as my container structure _somehow_, and I thought we established that can't be done... Thanks, Oren. On Mon, Sep 30, 2013 at 4:26 AM, Steven Blenkinsop steven...@gmail.comwrote: Yeah, I was trying to come up with a design a while ago to allow intrastructural borrowed pointers, and basically the effect this had was that you could never move anything out of the datastructure since that would leave dangling pointers. Which means you could grow the structure but never shrink it, which is sort of not good. Now my thought is about whether it would be possible to make a macro which allows you to define a safely encapsulated smart node which ensures that any intrastructural references meet certain invariants about where they point within the structure, but I haven't developed the idea enough to say whether you could make something truly general this way. On Sun, Sep 29, 2013 at 7:28 PM, Steven Fackler sfack...@andrew.cmu.eduwrote: Foo can't really be used safely. Say that we have struct Bar { baz: BazPartOfBar } struct Foo { bar: Bar, baz: 'magic BazPartOfBar } And let's say we add a `self` syntax to allow field initializers to refer to other fields: let foo = Foo { bar: Bar { baz: BazPartOfBar }, baz: self.bar.baz }; We can't really do much with Foo. If we move it, foo.baz is no longer a valid reference, so that can't happen. We could modify foo.bar in this case, but not if Bar were defined as struct Bar { baz: ~BazPartOfBar } since foo.baz would point to deallocated memory if we replace self.bar or self.bar.baz. Steven Fackler On Sun, Sep 29, 2013 at 3:15 PM, Tim Kuehn tku...@cmu.edu wrote: Could you use struct methods for quick access? Or is there a reason this wouldn't fit your use case? Sorry, I haven't followed the whole thread closely. struct Owner { owned: ~[int], } impl Owner { fn quick_access'a('a mut self) - 'a mut int { mut self.owned[0] } } ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
On Mon, Sep 30, 2013 at 8:31 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Huh, this is _exactly_ my use case. I have data structures which I grow but never shrink, and I never move anything out of them. This idiom isn't that uncommon when writing in functional style... I incrementally build a complex structure that allows quick access to the same pieces using different criteria (e.g., access a piece by a unique id, or look it up by a path, or via a direct pointer held by a related piece, etc.). All accesses are of (possibly mutable) borrowed pointers that live as long as the whole thing exist. Then when done I can discard the whole thing. Just a thought, but when you write incrementally build a complex structure ... discard the whole thing, I think arena allocation. That /might/ solve your borrowed pointer woes by letting you pervasively use borrowed pointers which all live at-most-as-long-as the arena (and hence the structure) itself. The borrow checker in my head is not advanced enough to let me really think it through though. And I don't think the compiler will let you send anything if there are borrowed pointers involved. There's an `arena` module[1] in libextra, but I've never tried it, and it uses `@` pointers internally which also precludes sending. (I wonder if there's any way to safely encode the idea that if all pointers are internal to the arena (there's nothing pointing in or out), then sending an ~arena should be safe, because its location in memory doesn't change. Presumably you would also need to move-send a pointer to the beginning of the structure inside of the arena alongside it. Maybe borrowed pointers are not the best fit here, or maybe they are, I dunno.) [1]: http://static.rust-lang.org/doc/master/extra/arena/struct.Arena.html Sometimes I have a less-complex structure to which I attach a related view structure. The view holds borrowed pointers to pieces of the original immutable structure, allowing efficient access in new and interesting ways. When done I can then discard the view and keep the original. So basically, I want something that gives me the freedoms granted to 'static, but only for as long as the main structure provably exists. Something like 'shadow :-) I found Rust doesn't like these idioms at all. I some cases, where I was too tired, performance wasn't an issue, and there was no need to send the whole thing between tasks, I just used @ pointers. Otherwise, I used RcMut, though this incurs boilerplate access code and hurts performance for no real reason. In critical cases I may end up using unsafe pointers... Using a macro - hmm. Interesting and if possible, would be a great solution. I'm not certain what such a macro would expand to, though. It would need to be something that would express the concept of I live only as long as my container structure _somehow_, and I thought we established that can't be done... Thanks, Oren. On Mon, Sep 30, 2013 at 4:26 AM, Steven Blenkinsop steven...@gmail.comwrote: Yeah, I was trying to come up with a design a while ago to allow intrastructural borrowed pointers, and basically the effect this had was that you could never move anything out of the datastructure since that would leave dangling pointers. Which means you could grow the structure but never shrink it, which is sort of not good. Now my thought is about whether it would be possible to make a macro which allows you to define a safely encapsulated smart node which ensures that any intrastructural references meet certain invariants about where they point within the structure, but I haven't developed the idea enough to say whether you could make something truly general this way. On Sun, Sep 29, 2013 at 7:28 PM, Steven Fackler sfack...@andrew.cmu.eduwrote: Foo can't really be used safely. Say that we have struct Bar { baz: BazPartOfBar } struct Foo { bar: Bar, baz: 'magic BazPartOfBar } And let's say we add a `self` syntax to allow field initializers to refer to other fields: let foo = Foo { bar: Bar { baz: BazPartOfBar }, baz: self.bar.baz }; We can't really do much with Foo. If we move it, foo.baz is no longer a valid reference, so that can't happen. We could modify foo.bar in this case, but not if Bar were defined as struct Bar { baz: ~BazPartOfBar } since foo.baz would point to deallocated memory if we replace self.bar or self.bar.baz. Steven Fackler On Sun, Sep 29, 2013 at 3:15 PM, Tim Kuehn tku...@cmu.edu wrote: Could you use struct methods for quick access? Or is there a reason this wouldn't fit your use case? Sorry, I haven't followed the whole thread closely. struct Owner { owned: ~[int], } impl Owner { fn quick_access'a('a mut self) - 'a mut int { mut self.owned[0] } } ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
On Monday, 30 September 2013, Oren Ben-Kiki wrote: Yes, it is very much like an arena... And yes, the idea is that all the pointers are contained in it, so the ~arena as a whole should be safe to send, but that contradicts using @ - maybe it could be re-written using Rc... hmmm. At any rate, thanks for the pointer - I wasn't aware of arenas before. Another hmmm... An arena sounds a lot like a weak version of a GC-ed heap... So here's a thought: What if @ pointers had a heap associated with them, just like pointers have a lifetime? We have the task-global @ heap, and we have the static lifetime... but we can explicitly manage lifetimes - how about if we could explicitly create a new Gc-heap use it to happily muck about with @'my-heap pointers (which would be statically prevented from being mixed with @'other-heap pointers), and be able to send the whole heap between tasks, etc.? (Not that I necessarily suggest @'heap as a syntax, but you get the idea) Gc would still run in the context of one heap at a time... but this would remove the restriction of one task = one heap. This would be neat, yes. In this case, accessing such a heap would be conceptually identical to temporarily joining a task, except without the overhead of having to schedule it, since it would have no independently executing code. Figuring out how to hook it into the GC would be a neat trick... As for what a macro would expand to, I was thinking more that it would expand to the containing structure and some smart references that use lifetimes to ensure that the containing structure is pinned during their existence and that they don't outlive it. You'd have to interact with it using methods which make sure you can't break any of the invariants, such as aliasing something and then trying to freeze it. To what extent you could do this statically rather than dynamically, I'm not sure, but lifetimes are a fairly powerful concept, so it's plausible one could work something out. Doing it dynamically would basically mean using Cells modified to have lifetimes as the smart references into the structure. It would be nice to have a version of the smart references that ensured you didn't externally alias something which is also externally mutable, though. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
I see what you mean about the macro - it would get quite complex though. Regardless of macros, neat extensions with GC heaps and arenas and so on... I still find it surprising that it is flat-out impossible to explicitly name the default lifetime of a struct, and also that the natural name for this lifetime ('self) is used for an entirely different purpose. It would be nice if we could rename the existing 'self to something (anything :-) else, and allow 'self to be used in struct field types and elsewhere for the more natural (and currently unavailable) lifetime of the current struct. Yes, this comes with some limitations, but it is useful for some interesting cases and its lack of an explicit name seems arbitrary (it is the default in many cases, after all). At any rate, I now have a better grasp of what is going on, so I have a better chance of writing code that actually works :-) Thanks for the explanations! On Mon, Sep 30, 2013 at 5:34 PM, Steven Blenkinsop steven...@gmail.comwrote: On Monday, 30 September 2013, Oren Ben-Kiki wrote: Yes, it is very much like an arena... And yes, the idea is that all the pointers are contained in it, so the ~arena as a whole should be safe to send, but that contradicts using @ - maybe it could be re-written using Rc... hmmm. At any rate, thanks for the pointer - I wasn't aware of arenas before. Another hmmm... An arena sounds a lot like a weak version of a GC-ed heap... So here's a thought: What if @ pointers had a heap associated with them, just like pointers have a lifetime? We have the task-global @ heap, and we have the static lifetime... but we can explicitly manage lifetimes - how about if we could explicitly create a new Gc-heap use it to happily muck about with @'my-heap pointers (which would be statically prevented from being mixed with @'other-heap pointers), and be able to send the whole heap between tasks, etc.? (Not that I necessarily suggest @'heap as a syntax, but you get the idea) Gc would still run in the context of one heap at a time... but this would remove the restriction of one task = one heap. This would be neat, yes. In this case, accessing such a heap would be conceptually identical to temporarily joining a task, except without the overhead of having to schedule it, since it would have no independently executing code. Figuring out how to hook it into the GC would be a neat trick... As for what a macro would expand to, I was thinking more that it would expand to the containing structure and some smart references that use lifetimes to ensure that the containing structure is pinned during their existence and that they don't outlive it. You'd have to interact with it using methods which make sure you can't break any of the invariants, such as aliasing something and then trying to freeze it. To what extent you could do this statically rather than dynamically, I'm not sure, but lifetimes are a fairly powerful concept, so it's plausible one could work something out. Doing it dynamically would basically mean using Cells modified to have lifetimes as the smart references into the structure. It would be nice to have a version of the smart references that ensured you didn't externally alias something which is also externally mutable, though. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
I've only skimmed this conversation, but note that the specialness of the 'self lifetime will be going away in the future. On Mon, Sep 30, 2013 at 10:48 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: I see what you mean about the macro - it would get quite complex though. Regardless of macros, neat extensions with GC heaps and arenas and so on... I still find it surprising that it is flat-out impossible to explicitly name the default lifetime of a struct, and also that the natural name for this lifetime ('self) is used for an entirely different purpose. It would be nice if we could rename the existing 'self to something (anything :-) else, and allow 'self to be used in struct field types and elsewhere for the more natural (and currently unavailable) lifetime of the current struct. Yes, this comes with some limitations, but it is useful for some interesting cases and its lack of an explicit name seems arbitrary (it is the default in many cases, after all). At any rate, I now have a better grasp of what is going on, so I have a better chance of writing code that actually works :-) Thanks for the explanations! On Mon, Sep 30, 2013 at 5:34 PM, Steven Blenkinsop steven...@gmail.comwrote: On Monday, 30 September 2013, Oren Ben-Kiki wrote: Yes, it is very much like an arena... And yes, the idea is that all the pointers are contained in it, so the ~arena as a whole should be safe to send, but that contradicts using @ - maybe it could be re-written using Rc... hmmm. At any rate, thanks for the pointer - I wasn't aware of arenas before. Another hmmm... An arena sounds a lot like a weak version of a GC-ed heap... So here's a thought: What if @ pointers had a heap associated with them, just like pointers have a lifetime? We have the task-global @ heap, and we have the static lifetime... but we can explicitly manage lifetimes - how about if we could explicitly create a new Gc-heap use it to happily muck about with @'my-heap pointers (which would be statically prevented from being mixed with @'other-heap pointers), and be able to send the whole heap between tasks, etc.? (Not that I necessarily suggest @'heap as a syntax, but you get the idea) Gc would still run in the context of one heap at a time... but this would remove the restriction of one task = one heap. This would be neat, yes. In this case, accessing such a heap would be conceptually identical to temporarily joining a task, except without the overhead of having to schedule it, since it would have no independently executing code. Figuring out how to hook it into the GC would be a neat trick... As for what a macro would expand to, I was thinking more that it would expand to the containing structure and some smart references that use lifetimes to ensure that the containing structure is pinned during their existence and that they don't outlive it. You'd have to interact with it using methods which make sure you can't break any of the invariants, such as aliasing something and then trying to freeze it. To what extent you could do this statically rather than dynamically, I'm not sure, but lifetimes are a fairly powerful concept, so it's plausible one could work something out. Doing it dynamically would basically mean using Cells modified to have lifetimes as the smart references into the structure. It would be nice to have a version of the smart references that ensured you didn't externally alias something which is also externally mutable, though. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
That's good! But there remains the fact that there's no way to say my lifetime is the same as the struct that contains me. If 'self specialness goes away, perhaps it can be re-introduced to mean that (or a different name can be given to it). On Mon, Sep 30, 2013 at 7:01 PM, Benjamin Striegel ben.strie...@gmail.comwrote: I've only skimmed this conversation, but note that the specialness of the 'self lifetime will be going away in the future. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
I think I should have put my code to gist to track changes easily. Amending: https://gist.github.com/dpx-infinity/6751843 2013/9/29 Vladimir Matveev dpx.infin...@gmail.com: Yes, this is what I have observed too, see issue https://github.com/mozilla/rust/issues/9597. I didn't know that using extra parameter with lifetime will help though. It indeed works. But I think that polluting traits-interfaces with lifetime annotation is wrong. Why the trait should have lifetime annotation? It is implementation detail. I just managed to do what I wanted with some kind of hack. The following code compiles and works: // Some business-logic trait trait Walker { fn walk(self); // Just self, without pointers } // ReaderContainer implementation remains the same // A struct which is intended to be an implementor of Walker trait // Note that it has lifetime parameter in order to work for any kind // of pointer to a Reader struct ReaderContainer'self { priv reader: 'self Reader, priv counter: int } // Some auxiliary structure for ReaderContainer // It may be anything but it should have a reference to ReaderContainer // We have to use lifetime parameter because this structure is 'attached' // to ReaderContainer, hence it must be of the same lifetime struct ReaderContainerIterator'self { priv container: 'self mut ReaderContainer'self } // Some made-up implementation of iterator protocol for our // auxiliary structure, it does not really matter impl'self Iteratoru8 for ReaderContainerIterator'self { fn next(mut self) - Optionu8 { if self.container.counter 10 { self.container.counter += 1; Some(self.container.reader.read_byte() as u8) } else { None } } } impl'self ReaderContainer'self { // A constructor for ReaderContainer, nothing special fn new'a(reader: 'a Reader) - ReaderContainer'a { ReaderContainer { reader: reader, counter: 0 } } // A method which returns our auxiliary structure, i.e. iterator // Note that self parameter has lifetime 'self, otherwise this naturally // does not compile fn iter('self mut self) - ReaderContainerIterator'self { ReaderContainerIterator { container: self } } } // And here are the changes // We implement Walker for a reference of the specific type! impl'self Walker for 'self mut ReaderContainer'self { // Here self automatically is 'self mut reference, so we can safely // use iter() method fn walk(self) { for b in self.iter() { println(fmt!(byte %?, b)); } } } fn main() { use std::io; let r = io::stdin(); let mut c = ReaderContainer::new(r); c.walk(); // No extra parameters } In short, I'm implementing `Walker` trait not for `ReaderContainer'self` but for `'self mut ReaderContainer'self`. This does not feel right, but I do not see immediate problems with this solution. Maybe someone who knows more about lifetimes could comment on this. 2013/9/29 David Renshaw dwrens...@gmail.com: If I drop the unused parameter, I get an internal compiler error: 'assertion failed: self.variance.is_some()' ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were that: - Every struct has a 'self lifetime, which is basically as long as this struct exists. It doesn't matter if I have a @ of the struct or a ~ of the struct or just a local variable with the struct... when the struct is dropped, the lifetime ends. - It follows there's no need to ever annotate structs as generic with a 'self parameter - it always exists. - Any in a struct is either 'self or 'static. A simple should be 'self as that makes more sense (but if Rust wants me to be explicit, fine). This were my least surprise expectations, but things don't work this way... the problem is I don't have a simple mental model to replace the above with, so I struggle. What _is_ 'self, exactly? Isn't a function fn foo(self) - T the same as returning a 'self T? Why would I want to say fn foo'a('a self) in the 1st place - 'a is by definition the same as 'self? How come David's Foo example fails the borrow check? Besides failing (my) least surprise expectations, the current rules also seem to be a leaky abstraction. If I have a struct that holds a ComplexT member, it needs no 'self parameter. If I then add a private member to my struct to hold some 'self PartOfT (say, cached access to an internal member), then boom, all uses of my struct now have to say 'self, I can no longer put it in thread-local-storage, etc. I'd expect keeping these sort of cached borrowed pointers should be an internal implementation detail which does not affect the users of the struct at all. I suppose there's a good reason for all this, and a reasonable mental model I need to put in my head, but digging around the docs I didn't find one... Any hints would be appreciated :-) On Sun, Sep 29, 2013 at 5:42 PM, David Renshaw dwrens...@gmail.com wrote: Cool! I think that solution is much better than mine. But I think that polluting traits-interfaces with lifetime annotation is wrong. Why the trait should have lifetime annotation? It is implementation detail. Just in case you want to see a case where it *does* make sense to put a 'self lifetime in a trait definition, here is an example: https://gist.github.com/dwrensha/db919b8e130e9eb72f0f ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics argument, the lifetime 'a is chosen by the caller of `foo` (as inferred by the compiler). Typically the caller will have an int object (i: int), then borrow a reference to it (r_int: 'a int = i) which it passes to `foo`, and then 'a will be the lifetime of the int. `foo` will then have to return a reference to (an int that lives at least as long). In practice this could either be the r_int it got as argument, or a static int. `fn foo(arg: int)` is shorthand for an anonymous lifetime parameter: `fn foo'a(arg: 'a int)` In the return type position `fn foo() - int` is short for `fn foo'a() - 'a int`, meaning `foo` has to return a reference to (an int that lives as long as any lifetime the caller could choose), which in practice means that it has to be 'static. I believe you are or will be required to write 'static explicitly in these cases to avoid confusion. With a struct it's not much different. s: MyStruct'a means lifetime_of(s) = 'a s: MyStruct'a, 'b means lifetime_of(s) = 'a lifetime_of(s) = 'b If you have struct MyStruct'self { r_int: 'self int } s: MyStruct'a then lifetime_of(s) = 'a lifetime_of(s.r_int) = 'a. (Which is trivial because lifetime_of(s) == lifetime_of(s.r_int).) Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. (Please yell at me if I got any of this wrong.) On Sun, Sep 29, 2013 at 5:23 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were that: - Every struct has a 'self lifetime, which is basically as long as this struct exists. It doesn't matter if I have a @ of the struct or a ~ of the struct or just a local variable with the struct... when the struct is dropped, the lifetime ends. - It follows there's no need to ever annotate structs as generic with a 'self parameter - it always exists. - Any in a struct is either 'self or 'static. A simple should be 'self as that makes more sense (but if Rust wants me to be explicit, fine). This were my least surprise expectations, but things don't work this way... the problem is I don't have a simple mental model to replace the above with, so I struggle. What _is_ 'self, exactly? Isn't a function fn foo(self) - T the same as returning a 'self T? Why would I want to say fn foo'a('a self) in the 1st place - 'a is by definition the same as 'self? How come David's Foo example fails the borrow check? Besides failing (my) least surprise expectations, the current rules also seem to be a leaky abstraction. If I have a struct that holds a ComplexT member, it needs no 'self parameter. If I then add a private member to my struct to hold some 'self PartOfT (say, cached access to an internal member), then boom, all uses of my struct now have to say 'self, I can no longer put it in thread-local-storage, etc. I'd expect keeping these sort of cached borrowed pointers should be an internal implementation detail which does not affect the users of the struct at all. I suppose there's a good reason for all this, and a reasonable mental model I need to put in my head, but digging around the docs I didn't find one... Any hints would be appreciated :-) On Sun, Sep 29, 2013 at 5:42 PM, David Renshaw dwrens...@gmail.comwrote: Cool! I think that solution is much better than mine. But I think that polluting traits-interfaces with lifetime annotation is wrong. Why the trait should have lifetime annotation? It is implementation detail. Just in case you want to see a case where it *does* make sense to put a 'self lifetime in a trait definition, here is an example: https://gist.github.com/dwrensha/db919b8e130e9eb72f0f ___ Rust-dev mailing list Rust-dev@mozilla.org
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
As far as I understand, you're mostly right, except the structures bit. Disregarding that it is not possible to use several lifetime parameters yet, I see only one slight mistake: `s: MyStruct'a` does not imply that `s` variable has any specific lifetime. If it is a local variable, then it has 'lexical' lifetime; if it is a field in a structure, it has lifetime of the structure instance. I guess what you meant is this: s: 'a MyStruct'a Here `s` pointer have lifetime 'a, as well as `s.r_int`. BTW, you came up with very nice math-like analogy, it helped me understand this thing even more. Thanks :) 2013/9/29 Gábor Lehel illiss...@gmail.com: 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics argument, the lifetime 'a is chosen by the caller of `foo` (as inferred by the compiler). Typically the caller will have an int object (i: int), then borrow a reference to it (r_int: 'a int = i) which it passes to `foo`, and then 'a will be the lifetime of the int. `foo` will then have to return a reference to (an int that lives at least as long). In practice this could either be the r_int it got as argument, or a static int. `fn foo(arg: int)` is shorthand for an anonymous lifetime parameter: `fn foo'a(arg: 'a int)` In the return type position `fn foo() - int` is short for `fn foo'a() - 'a int`, meaning `foo` has to return a reference to (an int that lives as long as any lifetime the caller could choose), which in practice means that it has to be 'static. I believe you are or will be required to write 'static explicitly in these cases to avoid confusion. With a struct it's not much different. s: MyStruct'a means lifetime_of(s) = 'a s: MyStruct'a, 'b means lifetime_of(s) = 'a lifetime_of(s) = 'b If you have struct MyStruct'self { r_int: 'self int } s: MyStruct'a then lifetime_of(s) = 'a lifetime_of(s.r_int) = 'a. (Which is trivial because lifetime_of(s) == lifetime_of(s.r_int).) Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. (Please yell at me if I got any of this wrong.) On Sun, Sep 29, 2013 at 5:23 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were that: - Every struct has a 'self lifetime, which is basically as long as this struct exists. It doesn't matter if I have a @ of the struct or a ~ of the struct or just a local variable with the struct... when the struct is dropped, the lifetime ends. - It follows there's no need to ever annotate structs as generic with a 'self parameter - it always exists. - Any in a struct is either 'self or 'static. A simple should be 'self as that makes more sense (but if Rust wants me to be explicit, fine). This were my least surprise expectations, but things don't work this way... the problem is I don't have a simple mental model to replace the above with, so I struggle. What _is_ 'self, exactly? Isn't a function fn foo(self) - T the same as returning a 'self T? Why would I want to say fn foo'a('a self) in the 1st place - 'a is by definition the same as 'self? How come David's Foo example fails the borrow check? Besides failing (my) least surprise expectations, the current rules also seem to be a leaky abstraction. If I have a struct that holds a ComplexT member, it needs no 'self parameter. If I then add a private member to my struct to hold some 'self PartOfT (say, cached access to an internal member), then boom, all uses of my struct now have to say 'self, I can no longer put it in thread-local-storage, etc. I'd expect keeping these sort of cached borrowed pointers should be an internal implementation detail which does not affect the users of the struct at all. I suppose there's a good reason for all this, and a reasonable mental model I
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
Thanks for the explanation. You said two key points: - Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. And: - 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. So, 'self is indeed very far from what I thought (hoped) it would be. Taking these together, do I read this right as saying there is no way whatsoever to say: struct Foo { bar: Bar, baz: 'i-live-as-long-as-the-foo-struct-and-no-more BazPartOfBar, } When writing a non-trivial container, I found several user cases to be extremely problematic. One was the above; a container held a spine or master or owned or whatever-you-want-to-call-it data structure(s), plus borrowed pointers that only live as long as the container and allow quick access to specific parts of it. Is this impossible in Rust (barring use of @ or unsafe pointers)? On Sun, Sep 29, 2013 at 8:24 PM, Gábor Lehel illiss...@gmail.com wrote: 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics argument, the lifetime 'a is chosen by the caller of `foo` (as inferred by the compiler). Typically the caller will have an int object (i: int), then borrow a reference to it (r_int: 'a int = i) which it passes to `foo`, and then 'a will be the lifetime of the int. `foo` will then have to return a reference to (an int that lives at least as long). In practice this could either be the r_int it got as argument, or a static int. `fn foo(arg: int)` is shorthand for an anonymous lifetime parameter: `fn foo'a(arg: 'a int)` In the return type position `fn foo() - int` is short for `fn foo'a() - 'a int`, meaning `foo` has to return a reference to (an int that lives as long as any lifetime the caller could choose), which in practice means that it has to be 'static. I believe you are or will be required to write 'static explicitly in these cases to avoid confusion. With a struct it's not much different. s: MyStruct'a means lifetime_of(s) = 'a s: MyStruct'a, 'b means lifetime_of(s) = 'a lifetime_of(s) = 'b If you have struct MyStruct'self { r_int: 'self int } s: MyStruct'a then lifetime_of(s) = 'a lifetime_of(s.r_int) = 'a. (Which is trivial because lifetime_of(s) == lifetime_of(s.r_int).) Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. (Please yell at me if I got any of this wrong.) On Sun, Sep 29, 2013 at 5:23 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were that: - Every struct has a 'self lifetime, which is basically as long as this struct exists. It doesn't matter if I have a @ of the struct or a ~ of the struct or just a local variable with the struct... when the struct is dropped, the lifetime ends. - It follows there's no need to ever annotate structs as generic with a 'self parameter - it always exists. - Any in a struct is either 'self or 'static. A simple should be 'self as that makes more sense (but if Rust wants me to be explicit, fine). This were my least surprise expectations, but things don't work this way... the problem is I don't have a simple mental model to replace the above with, so I struggle. What _is_ 'self, exactly? Isn't a function fn foo(self) - T the same as returning a 'self T? Why would I want to say fn foo'a('a self) in the 1st place - 'a is by definition the same as 'self? How come David's Foo example fails the borrow check? Besides failing (my) least surprise expectations, the current rules also seem to be a leaky abstraction. If I have a struct that
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
`On Sun, Sep 29, 2013 at 9:21 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Thanks for the explanation. You said two key points: - Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. And: - 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. So, 'self is indeed very far from what I thought (hoped) it would be. Taking these together, do I read this right as saying there is no way whatsoever to say: struct Foo { bar: Bar, baz: 'i-live-as-long-as-the-foo-struct-and-no-more BazPartOfBar, } Per my understanding, this is correct. Because there is a constraint on the lifetime of a part of `Foo`, there must a constraint on the lifetime of `Foo`. It has to propagate outwards to make sure the lifetime of the whole structure is properly constrained. You basically want to propagate inwards. I don't think that's possible, but maybe someone will correct me. When writing a non-trivial container, I found several user cases to be extremely problematic. One was the above; a container held a spine or master or owned or whatever-you-want-to-call-it data structure(s), plus borrowed pointers that only live as long as the container and allow quick access to specific parts of it. Is this impossible in Rust (barring use of @ or unsafe pointers)? This sounds similar to the case of a doubly linked list (with forward pointers being the spine and backwards the quick access), which is not possible as an 'owned' structure as far as I know without unsafe pointers. On Sun, Sep 29, 2013 at 8:24 PM, Gábor Lehel illiss...@gmail.com wrote: 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics argument, the lifetime 'a is chosen by the caller of `foo` (as inferred by the compiler). Typically the caller will have an int object (i: int), then borrow a reference to it (r_int: 'a int = i) which it passes to `foo`, and then 'a will be the lifetime of the int. `foo` will then have to return a reference to (an int that lives at least as long). In practice this could either be the r_int it got as argument, or a static int. `fn foo(arg: int)` is shorthand for an anonymous lifetime parameter: `fn foo'a(arg: 'a int)` In the return type position `fn foo() - int` is short for `fn foo'a() - 'a int`, meaning `foo` has to return a reference to (an int that lives as long as any lifetime the caller could choose), which in practice means that it has to be 'static. I believe you are or will be required to write 'static explicitly in these cases to avoid confusion. With a struct it's not much different. s: MyStruct'a means lifetime_of(s) = 'a s: MyStruct'a, 'b means lifetime_of(s) = 'a lifetime_of(s) = 'b If you have struct MyStruct'self { r_int: 'self int } s: MyStruct'a then lifetime_of(s) = 'a lifetime_of(s.r_int) = 'a. (Which is trivial because lifetime_of(s) == lifetime_of(s.r_int).) Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. (Please yell at me if I got any of this wrong.) On Sun, Sep 29, 2013 at 5:23 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were that: - Every struct has a 'self lifetime, which is basically as long as this struct exists. It doesn't matter if I have a @ of the struct or a ~ of the struct or just a local variable with the struct... when the struct is dropped, the lifetime ends. - It follows there's no need to ever annotate structs as generic with a 'self parameter - it always exists. - Any in a
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
That's... surprising. Even ignoring the fact the name self means exactly the opposite (déjà vu from const here)... I don't suppose there's a chance that something like what I expected 'self to be like would be supported at some point? Its lack rules out a lot of reasonable, safe, useful code. On Mon, Sep 30, 2013 at 12:13 AM, Gábor Lehel illiss...@gmail.com wrote: `On Sun, Sep 29, 2013 at 9:21 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Thanks for the explanation. You said two key points: - Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. And: - 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. So, 'self is indeed very far from what I thought (hoped) it would be. Taking these together, do I read this right as saying there is no way whatsoever to say: struct Foo { bar: Bar, baz: 'i-live-as-long-as-the-foo-struct-and-no-more BazPartOfBar, } Per my understanding, this is correct. Because there is a constraint on the lifetime of a part of `Foo`, there must a constraint on the lifetime of `Foo`. It has to propagate outwards to make sure the lifetime of the whole structure is properly constrained. You basically want to propagate inwards. I don't think that's possible, but maybe someone will correct me. When writing a non-trivial container, I found several user cases to be extremely problematic. One was the above; a container held a spine or master or owned or whatever-you-want-to-call-it data structure(s), plus borrowed pointers that only live as long as the container and allow quick access to specific parts of it. Is this impossible in Rust (barring use of @ or unsafe pointers)? This sounds similar to the case of a doubly linked list (with forward pointers being the spine and backwards the quick access), which is not possible as an 'owned' structure as far as I know without unsafe pointers. On Sun, Sep 29, 2013 at 8:24 PM, Gábor Lehel illiss...@gmail.com wrote: 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics argument, the lifetime 'a is chosen by the caller of `foo` (as inferred by the compiler). Typically the caller will have an int object (i: int), then borrow a reference to it (r_int: 'a int = i) which it passes to `foo`, and then 'a will be the lifetime of the int. `foo` will then have to return a reference to (an int that lives at least as long). In practice this could either be the r_int it got as argument, or a static int. `fn foo(arg: int)` is shorthand for an anonymous lifetime parameter: `fn foo'a(arg: 'a int)` In the return type position `fn foo() - int` is short for `fn foo'a() - 'a int`, meaning `foo` has to return a reference to (an int that lives as long as any lifetime the caller could choose), which in practice means that it has to be 'static. I believe you are or will be required to write 'static explicitly in these cases to avoid confusion. With a struct it's not much different. s: MyStruct'a means lifetime_of(s) = 'a s: MyStruct'a, 'b means lifetime_of(s) = 'a lifetime_of(s) = 'b If you have struct MyStruct'self { r_int: 'self int } s: MyStruct'a then lifetime_of(s) = 'a lifetime_of(s.r_int) = 'a. (Which is trivial because lifetime_of(s) == lifetime_of(s.r_int).) Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. (Please yell at me if I got any of this wrong.) On Sun, Sep 29, 2013 at 5:23 PM, Oren Ben-Kiki o...@ben-kiki.orgwrote: Ok, color me confused... perhaps there's somewhere that explains 'self on more detail? For example, _why_ does the example below not work without the explicit 'self? It seems like it should. I have yet to truly understand the whole 'self thing. When I first read about lifetimes, my naive expectations were
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
Foo can't really be used safely. Say that we have struct Bar { baz: BazPartOfBar } struct Foo { bar: Bar, baz: 'magic BazPartOfBar } And let's say we add a `self` syntax to allow field initializers to refer to other fields: let foo = Foo { bar: Bar { baz: BazPartOfBar }, baz: self.bar.baz }; We can't really do much with Foo. If we move it, foo.baz is no longer a valid reference, so that can't happen. We could modify foo.bar in this case, but not if Bar were defined as struct Bar { baz: ~BazPartOfBar } since foo.baz would point to deallocated memory if we replace self.bar or self.bar.baz. Steven Fackler On Sun, Sep 29, 2013 at 3:15 PM, Tim Kuehn tku...@cmu.edu wrote: Could you use struct methods for quick access? Or is there a reason this wouldn't fit your use case? Sorry, I haven't followed the whole thread closely. struct Owner { owned: ~[int], } impl Owner { fn quick_access'a('a mut self) - 'a mut int { mut self.owned[0] } } On Sun, Sep 29, 2013 at 5:32 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: That's... surprising. Even ignoring the fact the name self means exactly the opposite (déjà vu from const here)... I don't suppose there's a chance that something like what I expected 'self to be like would be supported at some point? Its lack rules out a lot of reasonable, safe, useful code. On Mon, Sep 30, 2013 at 12:13 AM, Gábor Lehel illiss...@gmail.comwrote: `On Sun, Sep 29, 2013 at 9:21 PM, Oren Ben-Kiki o...@ben-kiki.orgwrote: Thanks for the explanation. You said two key points: - Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. And: - 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. So, 'self is indeed very far from what I thought (hoped) it would be. Taking these together, do I read this right as saying there is no way whatsoever to say: struct Foo { bar: Bar, baz: 'i-live-as-long-as-the-foo-struct-and-no-more BazPartOfBar, } Per my understanding, this is correct. Because there is a constraint on the lifetime of a part of `Foo`, there must a constraint on the lifetime of `Foo`. It has to propagate outwards to make sure the lifetime of the whole structure is properly constrained. You basically want to propagate inwards. I don't think that's possible, but maybe someone will correct me. When writing a non-trivial container, I found several user cases to be extremely problematic. One was the above; a container held a spine or master or owned or whatever-you-want-to-call-it data structure(s), plus borrowed pointers that only live as long as the container and allow quick access to specific parts of it. Is this impossible in Rust (barring use of @ or unsafe pointers)? This sounds similar to the case of a doubly linked list (with forward pointers being the spine and backwards the quick access), which is not possible as an 'owned' structure as far as I know without unsafe pointers. On Sun, Sep 29, 2013 at 8:24 PM, Gábor Lehel illiss...@gmail.comwrote: 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics argument, the lifetime 'a is chosen by the caller of `foo` (as inferred by the compiler). Typically the caller will have an int object (i: int), then borrow a reference to it (r_int: 'a int = i) which it passes to `foo`, and then 'a will be the lifetime of the int. `foo` will then have to return a reference to (an int that lives at least as long). In practice this could either be the r_int it got as argument, or a static int. `fn foo(arg: int)` is shorthand for an anonymous lifetime parameter: `fn foo'a(arg: 'a int)` In the return type position `fn foo() - int` is short for `fn foo'a() - 'a int`, meaning `foo` has to return a reference to (an int that lives as long as any lifetime the caller could choose), which in practice means that it has to be 'static. I believe you are
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
Yeah, I was trying to come up with a design a while ago to allow intrastructural borrowed pointers, and basically the effect this had was that you could never move anything out of the datastructure since that would leave dangling pointers. Which means you could grow the structure but never shrink it, which is sort of not good. Now my thought is about whether it would be possible to make a macro which allows you to define a safely encapsulated smart node which ensures that any intrastructural references meet certain invariants about where they point within the structure, but I haven't developed the idea enough to say whether you could make something truly general this way. On Sun, Sep 29, 2013 at 7:28 PM, Steven Fackler sfack...@andrew.cmu.eduwrote: Foo can't really be used safely. Say that we have struct Bar { baz: BazPartOfBar } struct Foo { bar: Bar, baz: 'magic BazPartOfBar } And let's say we add a `self` syntax to allow field initializers to refer to other fields: let foo = Foo { bar: Bar { baz: BazPartOfBar }, baz: self.bar.baz }; We can't really do much with Foo. If we move it, foo.baz is no longer a valid reference, so that can't happen. We could modify foo.bar in this case, but not if Bar were defined as struct Bar { baz: ~BazPartOfBar } since foo.baz would point to deallocated memory if we replace self.bar or self.bar.baz. Steven Fackler On Sun, Sep 29, 2013 at 3:15 PM, Tim Kuehn tku...@cmu.edu wrote: Could you use struct methods for quick access? Or is there a reason this wouldn't fit your use case? Sorry, I haven't followed the whole thread closely. struct Owner { owned: ~[int], } impl Owner { fn quick_access'a('a mut self) - 'a mut int { mut self.owned[0] } } On Sun, Sep 29, 2013 at 5:32 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: That's... surprising. Even ignoring the fact the name self means exactly the opposite (déjà vu from const here)... I don't suppose there's a chance that something like what I expected 'self to be like would be supported at some point? Its lack rules out a lot of reasonable, safe, useful code. On Mon, Sep 30, 2013 at 12:13 AM, Gábor Lehel illiss...@gmail.comwrote: `On Sun, Sep 29, 2013 at 9:21 PM, Oren Ben-Kiki o...@ben-kiki.orgwrote: Thanks for the explanation. You said two key points: - Basically, every object has a lifetime - from its creation to its destruction - but a lifetime parameter or argument typically refers to the lifetime of something else, which the object itself must not or does not outlive. And: - 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. So, 'self is indeed very far from what I thought (hoped) it would be. Taking these together, do I read this right as saying there is no way whatsoever to say: struct Foo { bar: Bar, baz: 'i-live-as-long-as-the-foo-struct-and-no-more BazPartOfBar, } Per my understanding, this is correct. Because there is a constraint on the lifetime of a part of `Foo`, there must a constraint on the lifetime of `Foo`. It has to propagate outwards to make sure the lifetime of the whole structure is properly constrained. You basically want to propagate inwards. I don't think that's possible, but maybe someone will correct me. When writing a non-trivial container, I found several user cases to be extremely problematic. One was the above; a container held a spine or master or owned or whatever-you-want-to-call-it data structure(s), plus borrowed pointers that only live as long as the container and allow quick access to specific parts of it. Is this impossible in Rust (barring use of @ or unsafe pointers)? This sounds similar to the case of a doubly linked list (with forward pointers being the spine and backwards the quick access), which is not possible as an 'owned' structure as far as I know without unsafe pointers. On Sun, Sep 29, 2013 at 8:24 PM, Gábor Lehel illiss...@gmail.comwrote: 'self is not special in any way, except that the compiler has historical baggage such that 'self is the only name it lets you use for a lifetime parameter on a struct. But that's a bug. In the ideal platonic Rust in the sky, you can have any number of lifetime parameters on a struct with whatever names you prefer. The way I've found to think about lifetimes is that if you have: r_int: 'a int then 'a refers to a span of time (a scope, a lifetime) such that lifetime_of(r_int) = 'a = lifetime_of(*r_int). (Where *r_int is intended metaphorically to refer to the original object r_int was created from, not the result of the *r_int expression itself.) So 'a is a kind of stand between to ensure that r_int does not outlive the object it refers to. If you have fn foo'a(r_int: 'a int) - 'a int then just like any other generics
[rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
Hi all, The problem I'm writing about in this message follows from the one I have described in my other message: https://mail.mozilla.org/pipermail/rust-dev/2013-August/005281.html . I believe I'm now able to formulate it more clearly. Consider the following example code: trait Walker { // Some business-logic trait fn walk(mut self); } // A struct which is intended to be an implementor of Walker trait // Note that it has lifetime parameter in order to work for any kind // of pointer to a Reader struct ReaderContainer'self { priv reader: 'self Reader, priv counter: int } // Some auxiliary structure for ReaderContainer // It may be anything but it should have a reference to ReaderContainer // We have to use lifetime parameter because this structure is 'attached' // to ReaderContainer, hence it must be of the same lifetime struct ReaderContainerIterator'self { priv container: 'self mut ReaderContainer'self } // Some made-up implementation of iterator protocol for our // auxiliary structure, it does not really matter impl'self Iteratoru8 for ReaderContainerIterator'self { fn next(mut self) - Optionu8 { if self.container.counter 10 { self.container.counter += 1; Some(self.container.reader.read_byte() as u8) } else { None } } } impl'self ReaderContainer'self { // A constructor for ReaderContainer, nothing special fn new'a(reader: 'a Reader) - ReaderContainer'a { ReaderContainer { reader: reader, counter: 0 } } // A method which returns our auxiliary structure, i.e. iterator // Note that self parameter has lifetime 'self, otherwise this naturally // does not compile fn iter('self mut self) - ReaderContainerIterator'self { ReaderContainerIterator { container: self } } } // Here is the problem: we cannot implement Walker trait! impl'self Walker for ReaderContainer'self { // See below for concrete errors description fn walk(mut self) { // for b in self.iter() { println(fmt!(byte %?, b)); } } } fn main() { use std::io; let r = io::stdin(); let mut c = ReaderContainer::new(r); c.walk(); } This program does not compile with the following error: temp.rs:52:17: 52:30 error: cannot infer an appropriate lifetime due to conflicting requirements temp.rs:52 for b in self.iter() { ^ temp.rs:52:17: 52:22 note: first, the lifetime cannot outlive the expression at 52:17... temp.rs:52 for b in self.iter() { ^ temp.rs:52:17: 52:22 note: ...due to the following expression temp.rs:52 for b in self.iter() { ^ temp.rs:52:17: 52:30 note: but, the lifetime must be valid for the method call at 52:17... temp.rs:52 for b in self.iter() { ^ temp.rs:52:17: 52:22 note: ...due to the following expression temp.rs:52 for b in self.iter() { ^ error: aborting due to previous error This is somewhat expected, because `self` in `walk()` method implementation does not have 'self lifetime, so it is impossible to call `iter()` method which needs concrete 'self lifetime. But I cannot mark it with 'self lifetime either! If I do mark it with 'self: fn walk('self mut self) { // for b in self.iter() { println(fmt!(byte %?, b)); } } Then the program fails to compile with another message: temp.rs:51:4: 55:5 error: method `walk` has an incompatible type: expected concrete lifetime, but found bound lifetime parameter temp.rs:51 fn walk('self mut self) { // temp.rs:52 for b in self.iter() { temp.rs:53 println(fmt!(byte %?, b)); temp.rs:54 } temp.rs:55 } temp.rs:51:29: 55:5 note: expected concrete lifetime is the lifetime 'self as defined on the block at 51:29 temp.rs:51 fn walk('self mut self) { // temp.rs:52 for b in self.iter() { temp.rs:53 println(fmt!(byte %?, b)); temp.rs:54 } temp.rs:55 } error: aborting due to previous error This is also expected: adding 'self lifetime violates `Walker` trait signature, in which `walk()` method has plain `mut self` parameter. So, this is kind of dead end. I think this problem may be formulated in short as follows: how to implement generic traits for structures which have lifetime parameters which are used for `self` parameter in structure methods implementations? How to do what I want to do? Is it possible at all? Regards, Vladimir. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
If I add an unused parameter of type Option'self () to the walk() method, I can get your example to compile: https://gist.github.com/dwrensha/29ed998566e2f9218c18 On Sat, Sep 28, 2013 at 4:42 PM, Vladimir Matveev dpx.infin...@gmail.com wrote: Hi all, The problem I'm writing about in this message follows from the one I have described in my other message: https://mail.mozilla.org/pipermail/rust-dev/2013-August/005281.html . I believe I'm now able to formulate it more clearly. Consider the following example code: trait Walker { // Some business-logic trait fn walk(mut self); } // A struct which is intended to be an implementor of Walker trait // Note that it has lifetime parameter in order to work for any kind // of pointer to a Reader struct ReaderContainer'self { priv reader: 'self Reader, priv counter: int } // Some auxiliary structure for ReaderContainer // It may be anything but it should have a reference to ReaderContainer // We have to use lifetime parameter because this structure is 'attached' // to ReaderContainer, hence it must be of the same lifetime struct ReaderContainerIterator'self { priv container: 'self mut ReaderContainer'self } // Some made-up implementation of iterator protocol for our // auxiliary structure, it does not really matter impl'self Iteratoru8 for ReaderContainerIterator'self { fn next(mut self) - Optionu8 { if self.container.counter 10 { self.container.counter += 1; Some(self.container.reader.read_byte() as u8) } else { None } } } impl'self ReaderContainer'self { // A constructor for ReaderContainer, nothing special fn new'a(reader: 'a Reader) - ReaderContainer'a { ReaderContainer { reader: reader, counter: 0 } } // A method which returns our auxiliary structure, i.e. iterator // Note that self parameter has lifetime 'self, otherwise this naturally // does not compile fn iter('self mut self) - ReaderContainerIterator'self { ReaderContainerIterator { container: self } } } // Here is the problem: we cannot implement Walker trait! impl'self Walker for ReaderContainer'self { // See below for concrete errors description fn walk(mut self) { // for b in self.iter() { println(fmt!(byte %?, b)); } } } fn main() { use std::io; let r = io::stdin(); let mut c = ReaderContainer::new(r); c.walk(); } This program does not compile with the following error: temp.rs:52:17: 52:30 error: cannot infer an appropriate lifetime due to conflicting requirements temp.rs:52 for b in self.iter() { ^ temp.rs:52:17: 52:22 note: first, the lifetime cannot outlive the expression at 52:17... temp.rs:52 for b in self.iter() { ^ temp.rs:52:17: 52:22 note: ...due to the following expression temp.rs:52 for b in self.iter() { ^ temp.rs:52:17: 52:30 note: but, the lifetime must be valid for the method call at 52:17... temp.rs:52 for b in self.iter() { ^ temp.rs:52:17: 52:22 note: ...due to the following expression temp.rs:52 for b in self.iter() { ^ error: aborting due to previous error This is somewhat expected, because `self` in `walk()` method implementation does not have 'self lifetime, so it is impossible to call `iter()` method which needs concrete 'self lifetime. But I cannot mark it with 'self lifetime either! If I do mark it with 'self: fn walk('self mut self) { // for b in self.iter() { println(fmt!(byte %?, b)); } } Then the program fails to compile with another message: temp.rs:51:4: 55:5 error: method `walk` has an incompatible type: expected concrete lifetime, but found bound lifetime parameter temp.rs:51 fn walk('self mut self) { // temp.rs:52 for b in self.iter() { temp.rs:53 println(fmt!(byte %?, b)); temp.rs:54 } temp.rs:55 } temp.rs:51:29: 55:5 note: expected concrete lifetime is the lifetime 'self as defined on the block at 51:29 temp.rs:51 fn walk('self mut self) { // temp.rs:52 for b in self.iter() { temp.rs:53 println(fmt!(byte %?, b)); temp.rs:54 } temp.rs:55 } error: aborting due to previous error This is also expected: adding 'self lifetime violates `Walker` trait signature, in which `walk()` method has plain `mut self` parameter. So, this is kind of dead end. I think this problem may be formulated in short as follows: how to implement generic traits for structures which have lifetime parameters which are used for `self` parameter in structure methods implementations? How to do what I want to do? Is it possible at all? Regards, Vladimir.
Re: [rust-dev] Trait method self parameter type clashes with lifetime annotation required by the implementation
If I drop the unused parameter, I get an internal compiler error: 'assertion failed: self.variance.is_some()' ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev