I don't understant why the following code doesn't compile, and how to fix it. I want to create a function foo that take a closure closure as argument, witch itself accept a closure as argument. And I would like to have no Box or dyn.
Compiling playground v0.0.1 (/playground)
error: expected `;` or `{`, found keyword `fn`
--> src/lib.rs:5:8
|
5 | U: fn(i32) -> bool,
| ^^ expected `;` or `{`
error: aborting due to previous error
error: could not compile `playground`.
To learn more, run the command again with --verbose.
So what fixed, finite size should the compiler allocate for the closure? The purpose of the box or dyn is to provide a fixed-size fat pointer, so that the compiler can determine how much memory to allocate on the stack.
You can't. This is one of the limitations of Rust, because we lack Higher Rank Type Bounds (HRTB) we can't quantify over all types. This means you can't have a generic closure that can take another closure without sime sort of dynamic dispatch
Of course this wont let you use a closure, and you have to manually create a struct and implement the trait, but it's the closest you can get without dynamic dispatch.
@RustyYato Thanks, it's what I feared. For some reason whatever I try to write anything generic in rust, I try to write something that depend on HRTB. I guess I liked black magic too much in C++! While we wait that the language get them, wouldn't it be possible for the compiler have a better explanation about this limitation, or would it be too complicated?
Is the dynamic dispatch in this specific situation going to be elided away by the compiler, or would the dyn imply a runtime penalty?
About the solution you gave me, do you have a link to the documentation of what the for is in a where clause? I am still really new to rust, and never saw it before. It is just a way to introduce a new generic argument?
And finally, why did you write the lifetime annotation? If I remove it, it still compiles.
The syntax T: for<'a> Trait<'a> syntax means that for every choice of lifetime 'a, T should implement Trait<'a>, and is known as a higher ranked trait bound. Currently this kind of "for every choice of x" bound is only supported for lifetimes and not types, but you were looking for something like "for every choice of type U", which does not currently exist in Rust.
Sure, you can elide it in this case, but the compiler turns it into a for<'a> bound behind the scenes again if you do so.
The compiler might inline it enough to notice that it doesn't need dynamic dispatch, but there's no guarantee.
@alice is it possible to implement the Fn(i32) -> i32 trait for my struct (or whatever gives access to call syntax for a struct)? It would make the calling site nicer (foo(|f| f.call(32)) vs foo(|f| f(32))).