Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

document and justify temporary lifetime rules in the documentation #12032

Closed
nikomatsakis opened this Issue Feb 4, 2014 · 9 comments

Comments

Projects
None yet
7 participants
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Feb 4, 2014

The new syntax-based rules for temporary lifetimes that landed with #3511 have not yet been thoroughly documented outside the source. This should be fixed!

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Feb 6, 2014

1.0 blocker, P-low.

@pnkfelix pnkfelix added P-low and removed I-nominated labels Feb 6, 2014

@pnkfelix pnkfelix added this to the 1.0 milestone Feb 6, 2014

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Jun 11, 2014

Nominating for removal from milestone. We'll live if this isn't documented.

@brson brson added the I-nominated label Jun 11, 2014

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Jun 12, 2014

Removing from 1.0 milestone.

@pnkfelix pnkfelix removed this from the 1.0 milestone Jun 12, 2014

@steveklabnik steveklabnik added the A-docs label Feb 10, 2015

@steveklabnik

This comment has been minimized.

Copy link
Member

steveklabnik commented Feb 13, 2015

Traige: I'm not sure what these are exactly, maybe we can have a chat about them, @nikomatsakis ?

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Feb 14, 2015

@steveklabnik I would say


My go-to example of a gotcha here: Consider the following hypothetical desugaring of for-loop into more primitive constructs:

macro_rules! for_bad {
    (($pat:pat) in $head:expr { $($body:stmt)* }) => { {
        let mut iter = IntoIterator::into_iter($head);
        loop {
            match Iterator::next(&mut iter) {
                Some($pat) => { $($body)* }
                None => break,
            }
        }
    } }
}

The above is remarkably easy to read, at least for someone versed in macro_rules!: evaluate the input $head expression, convert it to an iterator, bind that result to iter, and then loop over the method calls to next.

Unfortunately, it does not work, and (according to my understanding), it is due to the R-value lifetime rules for temporaries.

In particular, consider: for_bad!( (k) in &[7,8,9] { println!("{}", k) } );; here, the temporaries created during the evaluation of:

        let mut iter = IntoIterator::into_iter($head);

only live to the end of that statement, not beyond. Thus the [7,8,9] in the head expression &[7,8,9] does not survive long enough for us to iterate over it!

So, what's the go-to fix for this? Its this: Bind via match instead of let, because match keeps its input alive for the entirety of the evaluation of the matched arm. (The main surprise to me here is that we need to use match to bind a non enum value.)

Here's that desugaring:

macro_rules! for_gud {
    (($pat:pat) in $head:expr { $($body:stmt)* }) => { {
        match IntoIterator::into_iter($head) {
            mut iter => loop {
                match Iterator::next(&mut iter) {
                    Some($pat) => { $($body)* }
                    None => break,
                }
            }
        }
    } }
}

And here's a playpen link to save you the trouble of transcribing the above into code if you want to play with it: http://is.gd/NmptIx

@sanxiyn

This comment has been minimized.

Copy link
Member

sanxiyn commented May 6, 2015

Any update? I wrote down some rules here: https://internals.rust-lang.org/t/borrow-scopes/1732

@taralx

This comment has been minimized.

Copy link
Contributor

taralx commented Jun 26, 2015

@pnkfelix Wouldn't it work to just bind $head with a let?

macro_rules! for_ok {
    (($pat:pat) in $head:expr { $($body:stmt)* }) => { {
        let head = $head;
        let mut iter = IntoIterator::into_iter(head);
        loop {
            match Iterator::next(&mut iter) {
                Some($pat) => { $($body)* }
                None => break,
            }
        }
    } }
}
@steveklabnik

This comment has been minimized.

@steveklabnik

This comment has been minimized.

Copy link
Member

steveklabnik commented Jul 7, 2015

After doing #26833 , @nikomatsakis and I decided to not actually go through this right now. At some point, we'll be developing a more formal model for Rust, and this information will belong there, but as it is, it feels weird in the reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.