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

First-class function can't call itself #7036

Closed
thinkpad20 opened this issue Jun 9, 2013 · 2 comments
Closed

First-class function can't call itself #7036

thinkpad20 opened this issue Jun 9, 2013 · 2 comments

Comments

@thinkpad20
Copy link

I'm not sure if this is an issue, but it sure seems to be. The following code:

fn main() {
    let collatz = |i: int, acc: int| -> int {
        if i == 1 { acc }
        else if i % 2 == 0 { collatz(i/2, acc + 1) }
        else { collatz(3*i + 1, acc + 1) }
    };
    println(fmt!("collatz(400) = %d", collatz(400, 0)));
}

Produces the following error on compilation:

> rustc collatz.rs
recurse.rs:4:23: 4:30 error: unresolved name: `collatz`.
recurse.rs:4        else if i % 2 == 0 { collatz(i/2, acc + 1) }
                                         ^~~~~~~
recurse.rs:5:9: 5:16 error: unresolved name: `collatz`.
recurse.rs:5        else { collatz(3*i + 1, acc + 1) }
                           ^~~~~~~
error: aborting due to 2 previous errors

Why is the function not aware of its own name?

@thinkpad20
Copy link
Author

Found out you can use an fn declaration for this:

fn main() {
    fn collatz (i: int, acc: int) -> int {
        if i == 1 { acc }
        else if i % 2 == 0 { collatz(i/2, acc + 1) }
        else { collatz(3*i + 1, acc + 1) }
    };
    println(fmt!("collatz(400) = %d", collatz(400, 0)));
}

@Aatch
Copy link
Contributor

Aatch commented Jun 9, 2013

@thinkpad20 Hi, I know you solved your problem, but I would like to explain why the first code didn't work. Apologies if you already figured this out, but maybe it'll help somebody else that stumbles across this issue.

For a start let foo = |x| x*x actually creates a closure, which is an anonymous function that potentially captures it's environment and assigns it to foo. Now, you might still be wondering why you couldn't call foo from inside that closure, after all, it is assigned to a variable. An example will help to explain:

fn main() {
  let foo = |x:int| x*x; // This creates a closure assigned to foo

  let foo = |x,y| {
    foo(x) + foo(y) // Which foo gets called?
  }
}

You can use let to introduce a new variable, and Rust really doesn't mind if it's the same name as a previous variable, as long as you don't mind not being able to access the previous variable any more. For this reason, captured variables in a closure are resolved before being assigned in an assignment expression. This provides a single rule for knowing which variables get captured when and where. In the above example, the first foo closure is captured by the second foo closure. A different rule would introduce ambiguity.

Again, apologies if you already worked this out but it doesn't hurt to have another explanation floating around.

flip1995 pushed a commit to flip1995/rust that referenced this issue Apr 8, 2021
consider mutability on useless_vec suggestions

fixes rust-lang#7035

changelog: Now the suggested by `useless_vec` considers mutability to suggest either `&[]`, as before, or `&mut []` if the used reference is mutable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants