Precedence of Variable Bound Closures over Named Functions during naming conflicts

When a Closure that has a Variable Binding is named "shape1" (i.e. let shape1 = | ... | { ... };), whilst a Named Function uses the same name "shape1" (i.e. fn shape1( ... ) -> ... { ... };), then why is it that the Closure takes precedence and always gets called, even regardless of the order in which they are declared?

In my example code below, the Closure gets called for "shape1" and "shape2" irrespective of whether the Named Function is declared before or after it. The compiler gives this warning message for both "shape1" and "shape2"

warning: function is never used: `square`, #[warn(dead_code)] on by default
fn square(dim: i32) -> i32 { dim * dim };

The only time that the Named Function gets called (instead of the Closure) is in the "shape3" example where the Closure has been removed entirely.

use std::old_io;

fn main() {
    try_closures();
}

fn try_closures() {

    fn twice<F: Fn(i32) -> i32>(dim: i32, f: F) -> i32 {
        f(dim) + f(dim)
    }

    // Variable Binding named 'shape1'
    let shape1 = |dim: i32| { dim * dim * dim * dim };
    // Named Function named 'shape1'
    fn shape1(dim: i32) -> i32 { dim * dim };

    // Evaluates using 'let shape1' to (10 * 10 * 10 * 10) = 20000
    println!("Double the input is: {}", twice(10, shape1) );

    // Named Function named 'shape2'
    fn shape2(dim: i32) -> i32 { dim * dim };
    // Variable Binding named 'shape2'
    let shape2 = |dim: i32| { dim * dim * dim * dim };

    // Evaluates using 'let shape2' to (10 * 10 * 10 * 10) = 20000
    println!("Double the input is: {}", twice(10, shape2) );

    // Named Function named 'shape3'
    fn shape3(dim: i32) -> i32 { dim * dim };

    // Evaluates using 'fn shape3' to (10 * 10) = 20000 (since it doesn't have a Closure to compete against anymore)
    println!("Double the input is: {}", twice(10, shape3) );

}

It happens because let shape2 = ... defines a variable, and variables shadow everything else, while fn shape2(...) defines an item (just like an fn outside a function). The order of items never matters in Rust.

2 Likes