4 ms·
What will `impl Trait` do, for us Rust-interested onlookers?
by cpr 9y ago
What will `impl Trait` do, for us Rust-interested onlookers?
- steveklabnik 9y agofn foo() -> impl Trait { means "this function returns something that implements the Trait trait, but I'm not gonna tell you what that concrete type is." This is primarily useful in two cases: first, in an effort for static dispatch, some types can get really long. For example, imagine you wanted to return an iterator of some kind, like this: foo.iter().map(|x| x + 1).filter(|x| x % 2 == 0) the type of this is something like Filter<Map<Iter<'_, {integer}>, [closure@<anon>:2:27: 2:36]>, [closure@<anon>:2:45: 2:59]> which is pretty gross. First of all, you'll notice the type `Filter<Map<Iter`, as you keep adapting the iterator, you get more types. With iterators it's normally not huge, but if you're using Tokio or Diesel, it can get very bad. Here's a type error I ran into recently with Diesel https://pbs.twimg.com/media/C6l_OwSXAAA_Fmo.jpg:large https://pbs.twimg.com/media/C6l_OwSXAAA_Fmo.jpg:large So, we could write fn foo() -> impl Iterator<Item=i32> { and be done, no matter how many adapters we use. In current Rust, you can do this: fn foo() -> Box<Iterator<Item=i32>> { but now you've introduced a heap allocation and dynamic dispatch; impl Trait has no allocations and statically dispatches. The second bit is also present in that type, which is this bit [closure@<anon>:2:27: 2:36] Closures have an anonymous type in Rust, and so you cannot write a function that returns a closure without using a Box like above. impl Trait will fix that, by letting you write fn foo() -> impl Fn(i32) -> i32 { or whatever the type of the closure is.
- jeeyoungk 9y agois there a RFC link for this? I got bitten by this once by attempting to return a derived iterator similar to `x.iter().map(...).filter(...)` example you had, but I couldn't figure out the return type of such function as Rust forbids type inferencing for return types.
- kzrdude 9y agoYes it hasn't been properly possible to return such an iterator chain that uses closures before, unless the iterator is manually boxed. With impl Trait that is now fixed. The latest RFC is https://github.com/rust-lang/rfcs/pull/1951 https://github.com/rust-lang/rfcs/pull/1951 ; it was in several.
- kibwen 9y ago> you cannot write a function that returns a closure This is true for your specific example, but in the interest of completeness there are cases where such a thing is possible. The full story is that you can't name the closure's type, so you can only write the type signature in certain cases. For example, the following function returns a stack-allocated closure just fine today (with example usage to prove it): fn foo<F: Fn(i32)->i32>(bar: F) -> F { bar } fn main() { let x = |y| { y + 2 }; let z = foo(x); z(5); } This is mostly pedantry, though, because it's true in that the majority of the time that you want to return a closure it's a closure that was created within that function, not passed in. This is where `impl Trait` is crucial.
- mrkgnao 9y agoWould that be related to an existential type of the form foo :: a -> (forall b. Show b => b) from Haskell?
- steveklabnik 9y agoYes, it is. Generics are universals and impl Trait is extisentials. For more, the RFC gets into it https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md#universals-any-versus-existentials-some https://github.com/rust-lang/rfcs/blob/master/text/1951-expa...
- kzrdude 9y agoExtends the reach of unboxed statically typed values. It's awesome in its power that way, while still using the same type checked trait model for generics.