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
Closed
Labels
P-low Low priority

Comments

@nikomatsakis
Copy link
Contributor

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
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
Copy link
Contributor

brson commented Jun 11, 2014

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

@pnkfelix
Copy link
Member

Removing from 1.0 milestone.

@pnkfelix pnkfelix removed this from the 1.0 milestone Jun 12, 2014
@steveklabnik
Copy link
Member

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

@pnkfelix
Copy link
Member

@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
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
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
Copy link
Member

@steveklabnik
Copy link
Member

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
Labels
P-low Low priority
Projects
None yet
Development

No branches or pull requests

7 participants