`On Sun, Sep 29, 2013 at 9:21 PM, Oren Ben-Kiki <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]>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
>>>> [email protected]
>>>> https://mail.mozilla.org/listinfo/rust-dev
>>>>
>>>
>>>
>>> _______________________________________________
>>> Rust-dev mailing list
>>> [email protected]
>>> https://mail.mozilla.org/listinfo/rust-dev
>>>
>>>
>>
>>
>> --
>> Your ship was destroyed in a monadic eruption.
>>
>
>


-- 
Your ship was destroyed in a monadic eruption.
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to