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

New Lint: No recursion without tail calls #1678

Open
Evrey opened this issue Apr 15, 2017 · 4 comments
Open

New Lint: No recursion without tail calls #1678

Evrey opened this issue Apr 15, 2017 · 4 comments
Labels
A-lint Area: New lints good-first-issue These issues are a good way to get started with Clippy L-perf Lint: Belongs in the perf lint group T-middle Type: Probably requires verifiying types

Comments

@Evrey
Copy link

Evrey commented Apr 15, 2017

Based on this HIC++ guideline.

The stack explodes much faster using recursion than a huge BFS work queue would explode the heap. Therefore, if clippy detects some direct or indirect recursion that does not benefit from tail call optimisation, clippy should issue a warning along with a short description about why this is potentially bad and a short hint on how to transform recursive algorithms to iterative ones (e.g. using a work queue and BFS). And maybe a tl;dr about what tail calls are and how to make the algorithm tail recursive.

@mcarton mcarton added L-perf Lint: Belongs in the perf lint group good-first-issue These issues are a good way to get started with Clippy A-lint Area: New lints T-middle Type: Probably requires verifiying types labels Apr 15, 2017
@llogiq
Copy link
Contributor

llogiq commented Apr 17, 2017

I'd like to note that Rust does not have guaranteed tail call optimization (yet).

@Evrey
Copy link
Author

Evrey commented Apr 17, 2017

I feared so. In that case the tail recursion hints would be a TODO for later.

@KamilaBorowska
Copy link
Contributor

And Rust cannot have guaranteed tail call optimization. For instance, in this program, all function calls (except for println! macro) are tail recursive, and yet, they cannot be optimized, as I use stack space as sorta heap.

struct LinkedList<'a> {
    prev: Option<&'a LinkedList<'a>>,
    value: u32,
}

fn so_linked<F: Fn(LinkedList)>(linked: LinkedList, callback: F) {
    let value = linked.value;
    if value == 0 {
        callback(linked);
    } else {
        so_linked(
            LinkedList {
                prev: Some(&linked),
                value: value - 1,
            },
            callback,
        );
    }
}

fn main() {
    so_linked(
        LinkedList {
            prev: None,
            value: 99,
        },
        |ref list| {
            let mut list = list;
            loop {
                println!("{}", list.value);
                if let Some(prev) = list.prev {
                    list = prev;
                } else {
                    break;
                }
            }
        },
    )
}

@oli-obk
Copy link
Contributor

oli-obk commented May 17, 2017

@xfix guaranteed tail call optimization means that your code would fail to compile iff rust-lang/rfcs#1888 get's accepted and you'd request tail call optimization by adding the become keyword to all tail call locations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints good-first-issue These issues are a good way to get started with Clippy L-perf Lint: Belongs in the perf lint group T-middle Type: Probably requires verifiying types
Projects
None yet
Development

No branches or pull requests

7 participants