Graydon Hoare wrote:
# Lifetime parameters and impls

...

This is *slightly* different than today.  This is because, today,
`&self` is equivalent to a self type of `&'b Iterator<'b, T>` rather
than using a fresh lifetime (like `&'a Iterator<'a, T>`).  The current
system causes various issues in real-life examples, including this
specific iterator example.

I do not entirely understand what the failure mode is. Are you saying
that today, an omitted lifetime parameter in an impl method signature
gets its default provided from the underlying type's lifetime parameter,
whereas in the new regime it will get a fresh parameter provided?

More or less, yes.

If so, I don't know the exact way it goes wrong (or really see it in the
example here), but it works better, I trust you know why, that's fine.

This is indeed what I mean and yes it can go wrong. Let me spell out what happens with the Iterator example, it's a bit involved and took me some time to fully appreciate. To begin, today you have the following annotations on the `next()` method, effectively:

    impl<'b, T> Iterator<'b, T> {
        fn next<T>(&'b mut self) -> Option<&'b T> { /* same as before */ }
    }

As you can see, both the lifetime of the `&mut self` pointer and the lifetime of the contents are `'b`. Now let's have an example of some code that invokes `next()`. This is the standard `find()` function for vectors, expressed with an iterator. It iterates down the list and returns the first item that matches some predicate `pred`. I have included all possible annotations and made all borrows explicit. Key lines are numbered in comments.

    fn find(v: &'lt [T], pred: &fn(&'lt T) -> bool) -> Option<&'lt T> {
        let iterator = Iterator(v);
        loop {
            let result: Option<&'lt T> =    /* [1] */
                (&'lt mut iterator).next(); /* [2] */
            match result {
                None => { return None; }
                Some(r) => {
                    if pred(r) {
                        return Some(r); /* [3] */
                    } else {
                        return None;
                    }
                }
            }
        }
    }

The lifetime of the input vector is 'lt. The signature promises to invoke the predicate function with data in the vector (and hence with the same lifetime) and to return an element of the vector (and hence with the same lifetime). The first important point is that, when we call `next()`, the lifetime of the resulting pointer must also be 'lt (as indicated in the type annotation [1]). This is because we are going to be returning this result if it matches the predicate ([3]). Now, because the lifetime of the pointer to the iterator and the lifetime of the iteratee are specified as the same ('b), this means that the lifetime of the borrow must be the same [2].

So, as a result of the above rules, the iterator is borrowed mutably for the full lifetime 'lt. This makes the borrow checker unhappy because it is only supposed to allow one mutable alias to iterator at a time, but the scope of the first mutable borrow outlives the enclosing loop (in fact, it outlives the entire `find()` function), and thus it seems to the borrow checker that you are creating new mutable aliases while the old ones still exist. Thus you get errors. These problems go away when you don't artificially conflate the lifetime attached to the `&self` pointer with the lifetime of the stuff it points at.

In general, I prefer this model anyhow because it treats `self` more like the other parameters to the function, which I think is somewhat less surprising and well simplify the specification and implementation.

Compatible and future-concern, defer.

Yes, adding label syntax is compatible and not something I particularly want to nail down now. The main reason that I mention it is that, with regard to pcwalton's desire for backwards-compatible language support, I would rather not be locked in to the current labeled loop system we have now.


regards,
Niko
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to