#Function "impl" Signature (Compile) vs Generic Trait Bounds (Fail)

13 messages · Page 1 of 1 (latest)

jolly bloom
#

I have encountered a situation where creating a function which returns a closure leaves me very confused as to why one syntax direction refuses to compile whereas another is allowed. I don't actually care about the functionality of the underlying code, as I'm merely analyzing it to better understand the language. Any direction as to an understanding why these two functions behave differently would be much appreciated.

Approach 1: The "Correct" Approach

fn legal_function<'a>(s: &'a String) -> impl Fn(String) -> bool + 'static
{
    let y = s.clone();
    let closure = move |x| {
        return x == y;
    };
    return closure;
}

Approach 2: My Personally "Preferred" Yet "Incorrect" Approach

fn illegal_function<'a, T>(s: &'a String) -> T
where 
    T: Fn(String) -> bool + 'static,
{
    let y = s.clone();
    let closure = move |x| {
        return x == y;
    };
    return closure;
}

The compiler gives the error every closure has a distinct type and so could not always match the caller-chosen type of parameter 'T'

I could accept that the function refuses to compile with any type ambiguity and BOTH the above functions refuse to compile. I am having a very difficult time accepting that for some reason Approach 1's ambiguity is allowed to compile from clearly SOME sort of type inference logic, and yet Approach 2's ambiguity is not allowed when the inner code blocks are identical. Thank you for your time if you read all this!

bleak yew
#

There's a key difference here:

With approach 1, you're saying "I return some type that implements Fn, but it's definitely that one type"

With approach 2, you're saying "I return any type that implements Fn, take your pick", which is very wrong

#

Approach 1 works because Rust can figure out what that exact type is, and make it statically work just as if you'd returned the type of the closure directly (which, fwiw, is impossible); approach 2 doesn't work because Rust can't just transmute your closure into whatever type the caller wants

jolly bloom
# bleak yew There's a key difference here: With approach 1, you're saying "I return *some* ...

I did a bit further investigation while I waited for a response. Your response was really good by the way thank you for your time and effort! Putting it into English words like this is very helpful. The conclusion I was slowly coming to as I waited for a response was

  • "Approach 1 allows the compiler to know the exact type because it's specified by the definition of the closure within the code block, yet the function caller has the concrete type opaqued and hidden from it (in its place exists only knowledge of the implemented type)"

meanwhile

  • "Approach 2 allows the function caller to know the exact type because it's specified within the generic, yet the compiler at compilation time does not know the type because like you said the specificity merely says 'any' type that implements Fn".
bleak yew
#

Yes, that's exactly it

jolly bloom
#

It does bring about the further thought experiment question of "What is the type of a closure" but that's probably numerous levels deeper than this question alone and this thread as it stands has been solved. Thank you again for your help!

bleak yew
#

Each closure has its own, unique type:

snow basin
bleak yew
#

?eval std::any::type_name_of_val(&(|| println!("hello, world!")))

shell riverBOT
#
"playground::main::{{closure}}"```
snow basin
#

(not actually a valid type name, but type_name has to return something)

jolly bloom
#

Did Ferris just throw a compilation error and then edit his own response 😭 Anyway, I'll see if there is any way to close or mark the thread solved now (I'm new to this). I believe I understand rather than just memorize now, thank you @bleak yew . And thank you @snow basin for answering my second question. I will lose the "beginner" tag someday at this rate 🙏

snow basin