4 ms·
I always thought unidirectional type inference (i.e. C++ 'auto') was good enough but I have been surprised to find omnidirectional type inference very useful in
by roca 6y ago
I always thought unidirectional type inference (i.e. C++ 'auto') was good enough but I have been surprised to find omnidirectional type inference very useful in Rust... for example, constructing an empty collection to pass as the parameter to a function.
- flumpcakes 6y agoDo you have any references about "omnidirectional type inference" in rust? A quick google doesn't bring anything obvious here. I am a bit confused here, are you talking about something that would require templates in C++? template <T> auto func(T t) { return t; } y = func<int>(5);
- steveklabnik 6y agoSome people describe this split as "type deduction" vs "type inference," that is, C++ has deduction, Rust has inference. Here is the gist of it. Inferring types in C++ (and languages with type deduction) basically looks like this: auto a = something; Here, the type of a is determined by the type of something. The left hand side determines the type of the right hand side. In Rust (and languages with type inference), inferring types can look like that: let a = something; but it can also "go backwards": let a = 5; let b: u64 = a; Here, a will be a u64, because you later assign it to something of type u64, and so the compiler can "work backwards" to infer this. (In my understanding, it does not literally work backwards, but it feels like it.) To see how this plays out in your parent's comment, I adapted the code from: https://docs.microsoft.com/en-us/cpp/cpp/auto-cpp?view=vs-2019 https://docs.microsoft.com/en-us/cpp/cpp/auto-cpp?view=vs-20... #include<vector> void func(std::vector<int> &vect) { vect.push_back(30); } int main() { std::vector<int> vect; vect.push_back(10); vect.push_back(20); func(vect); return 0; } You can't say "auto vect;" there, or else gcc will say "error: declaration of 'auto vect' has no initializer". But in Rust, you can write: fn func(vect: &mut Vec<i32>) { vect.push(30); } fn main() { let mut vect = Vec::new(); vect.push(10); vect.push(20); func(&mut vect); } no type annotation on "let mut vect" there; it can see that you eventually pass it to func, and that's enough to infer the type. (For completeness, the line would be "let mut vect: Vec<i32> = Vec::new();" if you wrote out the type.
- kibwen 6y agoAn additional short-and-sweet example, using HashMap: use std::collections::HashMap; fn main() { let mut foo = HashMap::new(); foo.insert("bar", 42); } In C++, the declaration of `foo` would require a type annotation like `map<string_view, int>`.
- steveklabnik 6y ago(you need foo.insert, but yes)
- kibwen 6y agoEr, you haven't heard about Rust's new feature where it treats all common metasyntactic variable names as interchangeable? :P
- steveklabnik 6y agoHa! Well, I just realized I messed up left and right in my post so... we all do it.