function A which take a function B as parameter, again the function B take function C as parameter. I try the syntax like below, but this gives me an error:
fn a(b: impl Fn(impl Fn() -> ()) -> ()) -> () {
// ...
}
error[E0666]: nested `impl Trait` is not allowed
--> src/main.rs:2:21
|
2 | fn a(b: impl Fn(impl Fn() -> ()) -> ()) -> () {
| --------^^^^^^^^^^^^^^^-------
| | |
| | nested `impl Trait` here
| outer `impl Trait`
For some reason, I can't use &dyn keyword:
fn a(b: impl Fn(&dyn Fn() -> ()) -> ()) -> () {
// ...
}
Are there another ways to do this?
And I don't know why nested impl Trait cause an error.
Nested impl Trait doesn't work because it hasn't been specified or implemented yet. Also, because it isn't very useful given how other parts of Rust work.
fn a(b: impl Fn(impl Fn() -> ()) -> ()) -> () can be written using full generic syntax as
fn a<B, C>(b: B) -> ()
where B: Fn(C) -> (),
C: Fn() -> ()
So what does that mean? It means that B is something callable that takes an argument of something else callable. But the important thing here is in the concrete types. Specifically, B doesn't take any callable with a compatible signature, but specifically a C. What is C? Well, that's the issue. If you call a like this:
a(|f| f());
then C is the type of the lambda's parameter f, but that type is not known, since the parameter f's type cannot be deduced from usage alone. But suppose that wasn't a problem, what would the body of a look like?
fn a<B, C>(b: B) -> ()
where B: Fn(C) -> (),
C: Fn() -> () {
b(|| ())
}
Here we attempt to call b passing lambda. But the lambda's type is unnamed local lambda type, not C. Since C was passed in from the outside, it cannot be the type of a lambda local to a. Simply put, unless you pass in a C as an additional parameter to a, there is nothing that a has that it could pass to b.
What you apparently want is for B to be not a function object that can be called with some C, but with any C. You want it to be a polymorphic function object. Rust doesn't support compile-time polymorphic function objects (the equivalent in Haskell would be a forall a. a -> IO () or similar). It only supports runtime polymorphic function objects.
That's the job of dyn. Now you've said you can't use &dyn, because you want to pass the function object to another thread. So instead, use Box<dyn>:
fn a(b: impl Fn(Box<dyn Fn() -> ()>) -> ()) -> () {
b(Box::new(|| println!("Hello")))
}
fn main() {
a(move |f| { f(); f(); });
}
Related
I have the following code (Playground):
// Two dummy functions, both with the signature `fn(u32) -> bool`
fn foo(x: u32) -> bool {
x % 2 == 0
}
fn bar(x: u32) -> bool {
x == 27
}
fn call_both<F>(a: F, b: F)
where
F: Fn(u32) -> bool,
{
a(5);
b(5);
}
fn main() {
call_both(foo, bar); // <-- error
}
To me, it seems like this should compile as foo and bar have the same signature: fn(u32) -> bool. Yet, I get the following error:
error[E0308]: mismatched types
--> src/main.rs:20:20
|
20 | call_both(foo, bar);
| ^^^ expected fn item, found a different fn item
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool {bar}`
The same error can be triggered with this code:
let mut x = foo;
x = bar; // <-- error
I also tried to cast bar to the function pointer type again:
let mut x = foo;
x = bar as fn(u32) -> bool; // <-- error
This resulted in a slightly different error:
error[E0308]: mismatched types
--> src/main.rs:20:9
|
20 | x = bar as fn(u32) -> bool;
| ^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool`
I don't understand these errors at all. What are fn items vs. fn pointers and why are foo and bar different fn items?
Function item vs. function pointer
When you refer to a function by its name, the type you get is not a function pointer (e.g. fn(u32) -> bool). Instead, you get an a zero-sized value of the function's item type (e.g. fn(u32) -> bool {foo}).
The value is zero-sized because it doesn't store the actual function pointer. The type perfectly identifies the function, so there is no need to store actual data in the type. This has several advantages, mostly about easier optimizations. A function pointer is like you would expect from other languages: it stores an address to the function.
A function pointer refers to the function via stored address; a function item refers to the function via type information.
A function item can be coerced to a function pointer in many situations, for example: as argument to a function and in let _: fn(u32) -> bool = foo; statements. Additionally, you can explicitly cast a function item to a function pointer: foo as fn(u32) -> bool.
You can read more about this topic in the reference on function items, function pointers and coercion.
Solution to your problem
In your case, the compiler isn't smart enough to figure out that you want the function pointers from your foo and bar instead of function items. When you call call_both(foo, bar) the compiler sets the generic type F to be fn(u32) -> bool {foo}, because that's the type of the first argument. And then it complains that the second argument doesn't have the same type.
You can fix that by explicitly specifying the F parameter:
call_both::<fn(u32) -> bool>(foo, bar);
call_both::<fn(_) -> _>(foo, bar); // <-- even this works
After specifying the type, the compiler can correctly coerce the arguments to a function pointer. You could also as-cast the first argument to fn(u32) -> bool explicitly.
You can fix your second example by explicitly stating the function pointer type, too:
let mut x: fn(u32) -> bool = foo;
x = bar;
In general: specifying the function pointer type somewhere to trigger the coercion will work.
Each named function has a distinct type since Rust PR #19891 was merged. You can, however, cast the functions to the corresponding function pointer type with the as operator.
call_both(foo as fn(u32) -> bool, bar as fn(u32) -> bool);
It's also valid to cast only the first of the functions: the cast will be inferred on the second, because both functions must have the same type.
call_both(foo as fn(u32) -> bool, bar);
I was told that Rust has a semantics in affine logic -- so one has deletion/weakening but not duplication/contraction.
The following compiles:
fn throw_away<A, B>(x: A, _y: B) -> A {
x
}
Because duplication is disallowed, the following does not compile:
fn dup<A>(x: A) -> (A, A) {
(x, x)
}
Similarly, neither of these compile:
fn throw_away3<A, B>(x: A, f: fn(A) -> B) -> A {
x;
f(x)
}
fn throw_away4<A, B>(x: A, f: fn(A) -> B) -> A {
throw_away(x, f(x))
}
Weakening is also witnessable
fn weaken<A, B, C>(f: fn(A) -> B) -> impl Fn(A, C) -> B {
move |x: A, y: C| f(x)
}
Instead of returning fn(A, C) -> B, we returned impl Fn(A, C) -> B. Is there a way to return fn(A, C) -> B instead? It's fine if not; I'm just curious.
Something else I expect is that you can lift A to () -> A. However, functions in Rust can be duplicated and used more than once. For example,
fn app_twice(f: fn(A) -> A, x: A) -> A {
f(f(x))
}
Suppose there was actually a function lift(x: A) -> fn() -> A, then we could break the move semantics. For example, this would allow
fn dup_allowed(x: A) -> (A, A) {
let h = lift(x);
(h(), h())
}
Thus to lift A to fn() -> A, we need to know that the function is "linear/affine" or can be used only once. Rust provides a type for this: FnOnce() -> A. In the following, the first compiles, and the second does not.
fn app_once(f: impl FnOnce(A) -> A, x: A) -> A {
f(x)
}
fn app_twice2(f: impl FnOnce(A) -> A, x: A) -> A {
f(f(x))
}
The following functions are inverses of each other (probably, I don't know Rust's semantics well enough to say that they are actually inverse to each other):
fn lift_up<A>(x: A) -> impl FnOnce() -> A {
move || x
}
fn lift_up_r<A>(f: impl FnOnce() -> A) -> A {
f()
}
Since fn dup<A>(x: A) -> (A, A) { (x,x) } does not compile, I thought that the following might be a problem:
fn dup<A>(x: fn() -> A) -> (A, A) {
(x(), x())
}
It seems that Rust is doing something special for fn(A) -> B types.
Why don't I have to declare that x is reusable/duplicable in the above?
Perhaps something different is going on. Declared functions are a bit special fn f(x: A) -> B { ... } is a particular witness that A -> B. Thus if f needs to be used multiple times, it can be reproved as many times as needed, but fn(A) -> B is a completely different thing: it is not a constructed thing but a hypothetical thing, and must be using that fn(A) -> Bs are duplicatable. In fact, I've been thinking that it's more like a freely duplicable entity. Here's my rough analogy:
fn my_fun<A,B>(x :A) -> B { M } "is" x:A |- M:B
fn(A) -> B "is" !(A -o B) hence freely duplicable
Thus fn() -> A "is" !(() -o A) = !A hence fn () -> A is the (co)free duplication on A
fn dup_arg<A: Copy>(x: A) -> B { M } "says" that A has duplication or is a comonoid
impl FnOnce (A) -> B "is" A -o B
But this can't be right... For what is impl Fn(A) -> B? From playing around a bit, it seems that fn(A) -> B is more strict than Fn(A) -> B. What am I missing?
fn weaken<A, B, C>(f: fn(A) -> B) -> impl Fn(A, C) -> B {
move |x: A, y: C| f(x)
}
Instead of returning fn(A, C) -> B, we returned impl Fn(A, C) -> B. Is there a way to return fn(A, C) -> B instead? It's fine if not; I'm just curious.
No, because a fn is by definition not a closure: it cannot contain any state that wasn't compiled into the program (in this case, the value of f). This is closely related to your next observation: because a fn cannot close over anything, it trivially cannot contain any non-Copy types and therefore can always be called multiple times, or itself copied, without violating the properties we're discussing.
Precisely: all fn(..) -> _ types implement Fn and Copy (as well as FnOnce).
Copy is the marker trait ('marker' meaning it provides no methods) that has the special purpose of telling the compiler that it is free to copy the bits of a type automatically whenever it is used more than once. Anything implementing Copy is opting out of the move-but-not-copy system -- but can't thereby violate the non-Copy-ness of a different type.
Fn is the trait for functions that can be called by immutable reference (not modifying or consuming the function itself). This is in principle separate from Copy, but it's very similar in effect; the differences that one could end up with (some of these can't happen in ordinary code) are:
If a function implements Fn but not Copy or Clone, then you can't store the function multiple places but you can call it as many times as you want.
If a function implements Copy but not Fn (only FnOnce), then this is invisible because every call of it (except for the last) implicitly copies it.
If a function implements Clone but not Fn or Copy, then you would have to .clone() it each time you called it (except the last).
And indeed the following functions are inverses of eachother (probably, I don't know rust's semantics well enough to say that they are actually inverse to each other):
fn lift_up<A> (x:A) -> impl FnOnce () -> A {move | | x}
fn lift_up_r<A> (f : impl FnOnce () -> A) -> A {f()}
lift_up_r accepts functions that lift_up did not produce; for example, if f has a side effect, panics, or hangs then let f = lift_up(lift_up_r(f)); has that effect. Ignoring that, they are inverses. An even better pair of inverses without that caveat would be functions for moving a value into a struct and back out -- which this is effectively doing, except for allowing inputs that aren't of that particular struct type.
Since fn dup (x:A) -> (A,A) {(x,x)} does not compile, I thought that the following might be a problem:
fn dup<A> (x : fn() -> A) -> (A,A) {(x(),x()}
But it seems that rust is doing something special for fn(A) -> B types. Finally, my question: why don't I have to declare that x is reusable/duplicable in the above?
When you have a generic function with a type variable, fn dup<A>, the compiler makes no assumptions about the properties of A (except that it is Sized unless you opt out of that implicit bound, because working with non-Sized values is highly restrictive and usually not what you want). In particular, it does not assume that A implements Copy.
On the other hand, as I mentioned above, all fn types implement Fn and Copy, so they can always be duplicated and reused.
The way to write a dup function which operates on general functions and fails to compile in the way you expect is:
fn dup<A, F>(x: F) -> (A,A)
where
F: FnOnce() -> A
{
(x(),x())
}
Here, we tell the compiler that F is a type of function which is consumed by calling it, and don't tell it about any way to duplicate F. So, it fails to compile with "error[E0382]: use of moved value: x". The shortest way to make this compile would be to add the bound F: Copy, and the most general would be to add F: Clone and an explicit .clone() call.
Perhaps something different is going on. Declared functions are a bit special fn f(x:A) -> B {...} is a particular witness that A -> B. Thus if f needs to be used multiple times, it can be reproved as many times as needed. But fn(A) -> B is a completely different thing: it is not a constructed thing but a hypothetical thing, and must be using a that fn(A) -> Bs are duplicatable. In fact, I've been thinking that it's more like a freely duplicable entity.
I'm no logician, but I think that the first half of this is not correct. In particular, (outside of some irrelevant considerations about generics) there are no properties that "a declared function" has that an arbitrary value of type fn(A) -> B does not have. Rather, the value of type fn(A) -> B can be copied, and that copiability corresponds directly to the fact that "it can be reproved", because (until we start introducing ideas like JIT code generation) every value of type fn(A) -> B refers to a compiled piece of code (and no other data) -- and hence a lemma that the compiler has checked and given the program license to reuse it as many times as needed at run time.
For what is impl Fn(A) -> B? From playing around a bit, it seems that fn(A) -> B is more strict than Fn(A) -> B. What am I missing?
The impl syntax serves different roles, but in argument position it is almost exactly a shorthand for generics. If I write
fn foo<A, B>(f: impl Fn(A) -> B) {}
then that is equivalent to
fn foo<A, B, F>(f: F)
where
F: Fn(A) -> B
{}
except that the caller is not allowed to specify any of the parameters when any impl argument types exist (this is not relevant to your interests but I mention it for accuracy). Thus, we're telling the compiler that F can be anything as long as it is callable as a reusable function. In particular, we're not specifying F: Copy or F: Clone. fn(A) -> B, on the other hand, is a concrete type which implements Fn(A) -> B and Copy, so you get that for free.
In return position, fn ... -> impl Fn(A) -> B, the impl denotes an existential type: you're asserting that there exists some type implementing Fn which the function will return. The compiler tracks the concrete type in order to generate code, but your program avoids naming it. This is necessary when returning a closure, but optional when returning a function that does not close over anything: for example, you can write
fn foo<A>() -> fn(A) -> A {
|x| x
}
I'm getting confused by this.
If the following works:
fn func_exit() -> bool {
println!("hi");
true
}
fn locate_func() -> fn() -> bool {
func_exit
}
Why these following syntaxes throw error?
fn locate_func1<F: Fn() -> bool>() -> F {
func_exit
}
fn locate_func2<F>() -> F where F:Fn() -> bool {
func_exit
}
I'm new to Rust and the following error message is not clear to me:
error[E0308]: mismatched types
--> src/main.rs:44:9
|
43 | fn locate_func1<F: Fn() -> bool>() -> F {
| - this type parameter - expected `F` because of return type
44 | func_exit
| ^^^^^^^^^ expected type parameter `F`, found fn item
|
= note: expected type parameter `F`
found fn item `fn() -> bool {func_exit}`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
error[E0308]: mismatched types
--> src/main.rs:47:9
|
46 | fn locate_func2<F>() -> F where F:Fn() -> bool {
| - - expected `F` because of return type
| |
| this type parameter
47 | func_exit
| ^^^^^^^^^ expected type parameter `F`, found fn item
|
= note: expected type parameter `F`
found fn item `fn() -> bool {func_exit}`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
Appreciate some help.
Thanks
fn locate_func() -> fn() -> bool {
func_exit
}
locate_func returns a pointer to a function returning bool (i.e. fn() -> bool).
fn locate_func1<F: Fn() -> bool>() -> F {
func_exit
}
locate_func1 means that the caller can specify any F satisfying the bounds Fn() -> bool, and it will return an F. But it is clearly not the case that func_exit is necessarily of the type specified by the caller.
locate_func2 has the same problem, just with where-Notation.
What you probably want could be the following:
fn locate_func3() -> impl Fn() -> bool {
func_exit
}
It says: locate_func3 returns something that implements the bound Fn() -> bool (and func_exit does so, so it can be returned there).
Also note the difference between fn (function pointers) and Fn ("something callable"):
The error is weird, but... you can't just return a bounded value like this, because bounded types are decided by the caller, and it doesn't make sense for the caller to decide what the return type is unless that return type is a consequence of an input type (e.g. an identity function is a trivial example of this). Which is not the case here.
If you want to return something generic, you need either some sort of trait object (so e.g. box the function and return a Box) or an impl (which still has a concrete return value but hides it at the API level).
The latter is more efficient but only allows returning a single concrete type, the former is less efficient but lets you return e.g. different closures.
I have the following code (Playground):
// Two dummy functions, both with the signature `fn(u32) -> bool`
fn foo(x: u32) -> bool {
x % 2 == 0
}
fn bar(x: u32) -> bool {
x == 27
}
fn call_both<F>(a: F, b: F)
where
F: Fn(u32) -> bool,
{
a(5);
b(5);
}
fn main() {
call_both(foo, bar); // <-- error
}
To me, it seems like this should compile as foo and bar have the same signature: fn(u32) -> bool. Yet, I get the following error:
error[E0308]: mismatched types
--> src/main.rs:20:20
|
20 | call_both(foo, bar);
| ^^^ expected fn item, found a different fn item
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool {bar}`
The same error can be triggered with this code:
let mut x = foo;
x = bar; // <-- error
I also tried to cast bar to the function pointer type again:
let mut x = foo;
x = bar as fn(u32) -> bool; // <-- error
This resulted in a slightly different error:
error[E0308]: mismatched types
--> src/main.rs:20:9
|
20 | x = bar as fn(u32) -> bool;
| ^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool`
I don't understand these errors at all. What are fn items vs. fn pointers and why are foo and bar different fn items?
Function item vs. function pointer
When you refer to a function by its name, the type you get is not a function pointer (e.g. fn(u32) -> bool). Instead, you get an a zero-sized value of the function's item type (e.g. fn(u32) -> bool {foo}).
The value is zero-sized because it doesn't store the actual function pointer. The type perfectly identifies the function, so there is no need to store actual data in the type. This has several advantages, mostly about easier optimizations. A function pointer is like you would expect from other languages: it stores an address to the function.
A function pointer refers to the function via stored address; a function item refers to the function via type information.
A function item can be coerced to a function pointer in many situations, for example: as argument to a function and in let _: fn(u32) -> bool = foo; statements. Additionally, you can explicitly cast a function item to a function pointer: foo as fn(u32) -> bool.
You can read more about this topic in the reference on function items, function pointers and coercion.
Solution to your problem
In your case, the compiler isn't smart enough to figure out that you want the function pointers from your foo and bar instead of function items. When you call call_both(foo, bar) the compiler sets the generic type F to be fn(u32) -> bool {foo}, because that's the type of the first argument. And then it complains that the second argument doesn't have the same type.
You can fix that by explicitly specifying the F parameter:
call_both::<fn(u32) -> bool>(foo, bar);
call_both::<fn(_) -> _>(foo, bar); // <-- even this works
After specifying the type, the compiler can correctly coerce the arguments to a function pointer. You could also as-cast the first argument to fn(u32) -> bool explicitly.
You can fix your second example by explicitly stating the function pointer type, too:
let mut x: fn(u32) -> bool = foo;
x = bar;
In general: specifying the function pointer type somewhere to trigger the coercion will work.
Each named function has a distinct type since Rust PR #19891 was merged. You can, however, cast the functions to the corresponding function pointer type with the as operator.
call_both(foo as fn(u32) -> bool, bar as fn(u32) -> bool);
It's also valid to cast only the first of the functions: the cast will be inferred on the second, because both functions must have the same type.
call_both(foo as fn(u32) -> bool, bar);
I have the following code (Playground):
// Two dummy functions, both with the signature `fn(u32) -> bool`
fn foo(x: u32) -> bool {
x % 2 == 0
}
fn bar(x: u32) -> bool {
x == 27
}
fn call_both<F>(a: F, b: F)
where
F: Fn(u32) -> bool,
{
a(5);
b(5);
}
fn main() {
call_both(foo, bar); // <-- error
}
To me, it seems like this should compile as foo and bar have the same signature: fn(u32) -> bool. Yet, I get the following error:
error[E0308]: mismatched types
--> src/main.rs:20:20
|
20 | call_both(foo, bar);
| ^^^ expected fn item, found a different fn item
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool {bar}`
The same error can be triggered with this code:
let mut x = foo;
x = bar; // <-- error
I also tried to cast bar to the function pointer type again:
let mut x = foo;
x = bar as fn(u32) -> bool; // <-- error
This resulted in a slightly different error:
error[E0308]: mismatched types
--> src/main.rs:20:9
|
20 | x = bar as fn(u32) -> bool;
| ^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
|
= note: expected type `fn(u32) -> bool {foo}`
found type `fn(u32) -> bool`
I don't understand these errors at all. What are fn items vs. fn pointers and why are foo and bar different fn items?
Function item vs. function pointer
When you refer to a function by its name, the type you get is not a function pointer (e.g. fn(u32) -> bool). Instead, you get an a zero-sized value of the function's item type (e.g. fn(u32) -> bool {foo}).
The value is zero-sized because it doesn't store the actual function pointer. The type perfectly identifies the function, so there is no need to store actual data in the type. This has several advantages, mostly about easier optimizations. A function pointer is like you would expect from other languages: it stores an address to the function.
A function pointer refers to the function via stored address; a function item refers to the function via type information.
A function item can be coerced to a function pointer in many situations, for example: as argument to a function and in let _: fn(u32) -> bool = foo; statements. Additionally, you can explicitly cast a function item to a function pointer: foo as fn(u32) -> bool.
You can read more about this topic in the reference on function items, function pointers and coercion.
Solution to your problem
In your case, the compiler isn't smart enough to figure out that you want the function pointers from your foo and bar instead of function items. When you call call_both(foo, bar) the compiler sets the generic type F to be fn(u32) -> bool {foo}, because that's the type of the first argument. And then it complains that the second argument doesn't have the same type.
You can fix that by explicitly specifying the F parameter:
call_both::<fn(u32) -> bool>(foo, bar);
call_both::<fn(_) -> _>(foo, bar); // <-- even this works
After specifying the type, the compiler can correctly coerce the arguments to a function pointer. You could also as-cast the first argument to fn(u32) -> bool explicitly.
You can fix your second example by explicitly stating the function pointer type, too:
let mut x: fn(u32) -> bool = foo;
x = bar;
In general: specifying the function pointer type somewhere to trigger the coercion will work.
Each named function has a distinct type since Rust PR #19891 was merged. You can, however, cast the functions to the corresponding function pointer type with the as operator.
call_both(foo as fn(u32) -> bool, bar as fn(u32) -> bool);
It's also valid to cast only the first of the functions: the cast will be inferred on the second, because both functions must have the same type.
call_both(foo as fn(u32) -> bool, bar);