Enormous sha2::Sha512 type signature?

I wrote a small function to return the Sha512 of a file's content. I auto-completed the function's return type and got this:

use sha2::{Digest, Sha512};
pub fn sha512_for<P: AsRef<Path>>(
    path_in: P,
) -> Result<
    sha2::digest::generic_array::GenericArray<
        u8,
        sha2::digest::typenum::UInt<
            sha2::digest::typenum::UInt<
                sha2::digest::typenum::UInt<
                    sha2::digest::typenum::UInt<
                        sha2::digest::typenum::UInt<
                            sha2::digest::typenum::UInt<
                                sha2::digest::typenum::UInt<
                                    sha2::digest::typenum::UTerm,
                                    sha2::digest::consts::B1,
                                >,
                                sha2::digest::consts::B0,
                            >,
                            sha2::digest::consts::B0,
                        >,
                        sha2::digest::consts::B0,
                    >,
                    sha2::digest::consts::B0,
                >,
                sha2::digest::consts::B0,
            >,
            sha2::digest::consts::B0,
        >,
    >,
    std::io::Error,
> {
    let mut hasher = Sha512::new();
    let file_content = std::fs::read(path_in)?;
    hasher.update(file_content);
    Ok(hasher.finalize())
}

In my short rust programming experience I had never seen such a beast. The return type is longer than the function body!
I'm wondering: how am I supposed to write such a type signature myself?
Am I missing something that make this more manageable ?

this is the normalized type that the tools see, but humans are using abstractions. there are shorthand (or alias) for it. unfortunately, sha2 uses the typenum crate for its encoded numeric types, which is not particularly newbie friendly. the type you should use here is: Result<GenericArray<u8, U64>, std::io::Error>.

the U64 is a type alias represents the type level unsigned integer 64, documentation:


some thoughts:

in languages with advanced type system like rust, you are supposed to write the signature first then the implementation, sometimes referred as type driven development.

the return type of a function cannot be inferred (if you are familiar with C++, there's no auto return type) in rust, and the tools cannot reliably autocomplete the type for complex types such as this one.

it takes some time to get comfortable with rust's powerful yet very complex type system, especially for new comers. yeah, they say rust has a deep learning curve, and I mostly agree. it would be really helpful if you have some prior functional programming experiences though.

4 Likes

Thanks for your answer!

I actually have experience with F# (which infers functions return types :wink: ), which eases my adoption of Rust, but this one was not obvious to interpret for me. I now see the U64 mentioned on this Sha512 doc page, but most types in the doc are very long too. You saved me a lot of time!

F# helps a lot.

here's a fun fact for you (in case you don't alread know): unlike many other "system programming langauges", the first rust compilers were not written in C/C++, but in OCaml (and thus has a great influence on the language)!

2 Likes