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

Allow reassigning a &mut to an inner pointer #11558

Closed
huonw opened this issue Jan 15, 2014 · 4 comments
Closed

Allow reassigning a &mut to an inner pointer #11558

huonw opened this issue Jan 15, 2014 · 4 comments
Labels
A-lifetimes Area: lifetime related

Comments

@huonw
Copy link
Member

huonw commented Jan 15, 2014

#[crate_type="lib"];

struct List {
    x: int,
    next: Option<~List>
}

#[cfg(invalid)]
pub fn each_loop(mut thing: &mut List, f: |&mut int|) {
    loop {
        f(&mut thing.x);

        match thing.next {
            None => break,
            // borrowck errors:
            Some(~ref mut next) => thing = next,
        }
    }
}

pub fn each_rec(thing: &mut List, f: |&mut int|) {
    f(&mut thing.x);

    match thing.next {
        None => {},
        Some(ref mut next) => each_rec(*next, f),
    }
}

each_loop is invalid, but each_rec is ok.

My feeling is that the loop form should be valid, since the thing object is erased, and so the thing and next borrows do not overlap or alias (that is, the old object to which thing pointed is inaccessible). However I could easily be wrong.

Allowing the first would allow us to write code that is guaranteed to be efficient; although LLVM does perform TCO often so it isn't completely necessary. (That said, LLVM doesn't TCO each_rec, the closure seems to be interfering: with the closure call it is still recursive, but with just thing.x += 1 it is optimised to a loop)

(The equivalent thing with & instead of &mut is already valid.)

@huonw
Copy link
Member Author

huonw commented Jan 15, 2014

cc @nikomatsakis

@alexcrichton
Copy link
Member

This is possible, you just have to do a little dance:

pub fn each_loop(mut thing: &mut List, f: |&mut int|) {
    loop {                                             
        f(&mut thing.x);                               

        let tmp = thing;                               
        match tmp.next {                               
            None => break,                             
            Some(~ref mut next) => {                   
                thing = next;                          
            }                                          
        }                                              
    }                                                  
}                                                      

@huonw
Copy link
Member Author

huonw commented Jan 15, 2014

Oh, wow. Magic!

I guess this bug is now for doing it without the dance.

@nikomatsakis
Copy link
Contributor

Dup of #10520 I think

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: lifetime related
Projects
None yet
Development

No branches or pull requests

3 participants