Is it monomorphization?

For this code ...

fn id_a <T>(v: T) -> T { return v; }
fn hof <'i, T: 'i>(f: Box<dyn 'i + Fn (T) -> T>) -> Box<dyn 'i + Fn (T) -> T> {
    return Box::new(|arg|{
        return (*f) (arg);
    });
} 
fn main() {
    let k = hof (Box::new(id_a));
    (|| {
        let a = rand::random::<bool>();
        if a { k (0); };
        if !a { k (""); }; //error here
    }) ();
}

... compiler shows an error: expected integer, found '&str'.
I assume this happens because of monomorphisation. Is there a way to call it with different types?

Yeah, it happens because it's trying to figure out what T is in the call to hof, but if you use two different types for T, it will fail to make a choice.

To answer the question, you cannot define a "generic" boxed closure.

That's sad (

Not really.

Even if you could use higher-kinded types to accept a closure which is generic over its argument type (i.e. F: for<T> Fn(T) -> T), using dynamic dispatch (the Box<dyn Foo> syntax) with such a closure would actually be nonsensical.

Dynamic dispatch works by creating a structure called a "vtable" containing function pointers for all the object's methods (just call() for Fn(...) types), but if our closure was able to be called with any type then the vtable would need to contain an infinite number of function pointers and rustc would need to generate code for deciding which version to call at runtime.

The higher-order function you are trying to create would work if HKTs were extended to work for types and not just lifetimes, but that isn't implemented in Rust's type system (yet?).

On the topic of "generic callbacks" there is an explanation of how to use traits to the same effects in Rayon's docs https://github.com/rayon-rs/rayon/blob/v1.5.0/src/iter/plumbing/README.md -- see the part about ProducerCallback.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.