Announcing Rust 1.18
blog.rust-lang.org
blog.rust-lang.org
fn 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:largeSo, 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.The latest RFC is https://github.com/rust-lang/rfcs/pull/1951 ; it was in several.
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. foo :: a -> (forall b. Show b => b)
from Haskell?Good to hear work is being done to speed up the compiler. It's the only reason I haven't tried Rust out yet, as it often comes up as a problem when others review the language.
To be clear though, this PR is about improving the speed of compiling the compiler, not for using the compiler on other programs.
[1]: https://github.com/rust-lang/rust/compare/cb4065b9ce4e2bb2c3...
Whole bunch of perf fixes at once.
Does this mean you can now build Android targets without a standalone NDK? That part wasn't quite clear from the PR.
https://github.com/rust-lang/cargo/pull/3885/files#diff-27a1... would imply to me that oyu still need an NDK.
Yeah, the Standalone NDK is a bit of a pain since the .cargo/config requires absolute paths to the linker/ar. It makes it hard to commit a common config file for multiple people working in one repo.
[target.arm-linux-androideabi]
ar = "arm-linux-androideabi-ar"
linker = "arm-linux-androideabi-gcc"The short of it is "it's all in various stages of development, nothing has hit stable yet." I don't think there's anything major in the next release either, the one after that may or may not have something, we'll see.
- quoting Jon Carmack -
whatever the compiler allows in, will eventually be included in your codebase
It's an improvement over C. But where were the hard decisions? Where is the line in the sand on safety? (I am hopingg to bbe educatted! ; ))
It's not the future, just more of the past.