I have two similar code snippets, one uses return keyword and other doesn't,
the one with return statement gives compiler error "expected closure" found fn pointer.
while one without return keyword compiles. why the difference ?
Interesting. Apparently the return makes the compiler decide the closure type is the opaque type you're going to return, whereas without it the compiler managed to unify the types of the two branches (by coerce both closures to fn(Vec<String>)).
Interesting. I'm not completely sure I know what's happening, but I'll give it a shot. I think the problem is that the first function makes each closure be evaluated separately, not really the return keyword per say. This version actually works:
Closures are kind of funny. Even though both closures implement the Fn(Vec<String>) trait, each instance is its own unique type. The return keyword basically says "break normal control flow early with this value." Each closure is considered individually, so the compiler has to coerce them into the same type. The next closest thing is a function pointer. Because both closures have the same arguments and return type, they actually are the same type fn.
Yeah, that's a bit confusing. The trait Fn(Vec<String>) is how you describe a closure, and the type fn(Vec<String>) is a function pointer. Two different closures can never be the same type, but using them is a little bit more flexible. Basically, if you're okay with using a function pointer, then this works:
Short version, something about having both closures in a single expression lets the compiler unify the types as a closure. Breaking them apart into separate return expressions makes the type evaluated separately for each one, then they need to be coerced into function pointers as a second step to unify the types.
In the no_error (no return) case, the two closures are first "unified" against each other (as the two branches of an if-expression) resulting in coercion into a fn pointer, which is then "unified" against return type which just sets the return type to that fn pointer.
In the error (return) case, the first closure is "unified" against the return type (because it is an argument of a return statement) which sets the return type to type of that closure, then the second closure is "unified" against the return type (which has been already set to the first closure type), which fails (the two closures have different types and adding a coercion is probably not considered by compiler here)
It is random sample which I was playing with and stumbled on diverse compilation. I understand that args argument was not used. I should have removed it while posting.