43

impl Traits can be used as function arguments. Are there differences between this and a generic function with a trait constraint?

trait Foo {}

fn func1(_: impl Foo) {}

fn func2<T: Foo>(_: T) {}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Boiethios
  • 38,438
  • 19
  • 134
  • 183

2 Answers2

34

impl Traits as function arguments are desugared to an anonymous generic parameter. See the RFC, which says:

Expand impl Trait to allow use in arguments, where it behaves like an anonymous generic parameter.

There's also an example in the RFC:

// These two are equivalent
fn map<U>(self, f: impl FnOnce(T) -> U) -> Option<U>
fn map<U, F>(self, f: F) -> Option<U> where F: FnOnce(T) -> U

However, one difference is that impl Trait arguments cannot have their types explicitly specified:

fn foo<T: Trait>(t: T)
fn bar(t: impl Trait)

foo::<u32>(0) // this is allowed
bar::<u32>(0) // this is not

The Motivation for expanding to argument position section explains why additional syntax was added for an existing feature. In short, it's for having similar syntax as impl traits in function return position, which improves learnability, and to improve ergonomics.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
interjay
  • 107,303
  • 21
  • 270
  • 254
  • Hm, thanks. I did not read the RFC; I only saw the link to the github issue from "this week in Rust". – Boiethios Nov 27 '17 at 16:41
  • 1
    @Boiethios RFCs, even merged RFCs, aren't always accurate to the current version of Rust -- they may be not-yet-implemented, implemented-with-changes, or superseded -- so it's still a fair question. However, in this case the RFC is accurate. – trent Nov 27 '17 at 18:43
  • (When changes have been made since the RFC was merged, you'd hope to find that in the tracking issue for the RFC.) – trent Nov 27 '17 at 18:45
8

Both produce identical assembly, at least with the following simple test case:

trait Foo {}

struct Bar;

impl Foo for Bar {}

fn func1(_: impl Foo) {}

fn func2<T: Foo>(_: T) {}

fn main() {
    let x = Bar;

    let y = func1(x); // or func2(x);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
ljedrz
  • 20,316
  • 4
  • 69
  • 97