I prefer Rust's way of doing this. When you're a beginner it ensures that you're passing and returning the proper type to and from the function, you kind of have the function as a guard which ensures that you're using the correct types.
I prefer Rust's way of doing this. When you're a beginner it ensures that you're passing and returning the proper type to and from the function, you kind of have the function as a guard which ensures that you're using the correct types.
You don't need it for all function declarations though, there are many trivial cases where type signatures don't add value. Consider that you probably would prefer most of the variables within a function to be inferred for you by the compiler. A similar thing could be said about the most of the functions within a given module. Important interface methods can be defined explicitly though, for extra clarity and self-documenting purposes.
module functions: if I chose, I'd let them be derived, but I'm relatively indifferent
inner functions: should be allowed to be derived, IMO. They're very infrequently used so this choice doesn't have much impact.
It's certainly good practise to write out your types, and often your editor can do it for you, but there are tons of little places where it's a waste.
Lifetime annotations aren't elided based on there being only one unambiguous answer. Rather, there's three simple rules[1] that look at the function signature and in simple cases give what you probably want. If those simple rules don't match your use case you need to define manually, the compiler doesn't get clever.
This means that if you want to take a reference to an array and return a reference to an item in an array, for example, elision will work fine. But if you take a reference to a key and look up a reference to the value in a global map you need to write it by hand, even though the compiler could pretty clearly guess the output lifetime you want.
This preserves a crucial feature: you can know the exact signature of a function by only looking at the signature definition, you don't need to look into the body.
Lifetime elision isn't like inferring argument types. It's like defaulting integer literals to i32 unless you specify otherwise.