News for hackers. Stuff that matters.
Re:Rust 1.25 released by Buttons840 on Thursday March 29, 2018 @11:00AM (#16707590)
I'm out of the loop. How will "impl Trait" help with errors? Does it automatically improve errors, or just allow library authors to implement custom error or something?
Re:Rust 1.25 released by steveklabnik on Thursday March 29, 2018 @11:13AM (#16707672)
Consider this code:

  fn foo_no(v: &[i32]) -> std::iter::Cloned<std::slice::Iter<i32>> {
      v.iter().cloned()
  }

  fn foo_impl<'a>(v: &'a [i32]) -> impl Iterator<Item=i32> + 'a {
      v.iter().cloned()
  }

  fn main() {
      let v = vec![1, 2, 3];
    
      let () = foo_no(&v);
      let () = foo_impl(&v);
  }
Given the let ()s, this will fail to compile for both. For the first, you get

  = note: expected type `std::iter::Cloned<std::slice::Iter<'_, i32>>`
for the second, you get

  = note: expected type `impl std::iter::Iterator`
The former gets longer and longer based on how many iterator chains you do, the latter will be the same no matter how many you add. It's also just generally way more clear, "I was expecting something implementing Iterator, and I didn't get it" vs "I was expecting this exact chain of nested iterators".
Re:Rust 1.25 released by mike-cardwell on Thursday March 29, 2018 @02:11PM (#16709473)
Can you explain why an explicit lifetime is needed in foo_impl? I don't see a connection between the function argument lifetime and the return value lifetime, as the return value is a brand new object with cloned values... I realise I'm missing something fundamental here.
Re:Rust 1.25 released by steveklabnik on Thursday March 29, 2018 @03:02PM (#16710084)
okay so, the un-elided version of foo_no is

  fn foo_no<'a>(v: &'a [i32]) -> std::iter::Cloned<std::slice::Iter<'a, i32>> {
I am not sure why the impl Trait version doesn't elide properly; I wrote it without the lifetime first and the compiler told me I need it, so I wrote it out, which is often what happens to me in these situations. I assume, since the elision rules were written years before impl Trait became a thing, that there's some sort of reason why it doesn't elide, but honestly, I'm not sure.
Re:Rust 1.25 released by mike-cardwell on Thursday March 29, 2018 @03:13PM (#16710173)
So why is the lifetime of the return value linked to the lifetime of the function argument? Couldn't the return value live longer than the function argument in that example?
Re:Rust 1.25 released by steveklabnik on Thursday March 29, 2018 @03:51PM (#16710481)
In both cases, the iterators are over the slice, so their lifetimes need to be tied together. The iterator can't live longer than the slice, or it'd be a use after free. Does that make sense?
Re:Rust 1.25 released by mike-cardwell on Thursday March 29, 2018 @04:27PM (#16710746)
Yes. Thanks for the explanation.
Re:Rust 1.25 released by irishsultan on Thursday March 29, 2018 @04:30PM (#16710771)
The Cloned iterator clones the elements of the underlying iterator, but only on-demand, so obviously it can't do that once the argument isn't live anymore.
Re:Rust 1.25 released by Buttons840 on Thursday March 29, 2018 @01:11PM (#16708779)
Ok. It looks like the new feature allows library authors to express their intentions with simpler code, and thus error messages will also be simpler. Looks good, thanks for taking the time to answer my question.
Re:Rust 1.25 released by steveklabnik on Thursday March 29, 2018 @01:15PM (#16708830)
No problem! It also does enable some other things too. For example, closures have a type that's not writable, so

  fn foo() -> impl Fn(i32) -> i32 {
      |x| x + 1
  }
can be written, since closures implement the Fn trait, but there's no way to write the type directly.