Why can't you call a function with APIT with generic parameters?

fn bar<T: Send>(t: T) {}
fn foo(t: impl Send) { }

fn main() {
    let b = bar::<i32>(10);
    let f = foo::<i32>(10); // <-- Error here
}

One would think that impl Send is just sugar for the generic. Why doesn't this work?

I think this discussion from the time the current design was stabilized highlights some of the thoughts behind the current design, and possible alternatives:

https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Stabilization.20of.20.60explicit_generic_args_with_impl_trait.60/near/270916184

3 Likes

I have two answers:

  1. Because once the function has multiple, say fn qux(x: impl Foo<impl Bar, Output = impl Zoo>), it's no longer obvious to me that turning all these into generic parameters that can be turbofished is a good idea, and while one could make a rule for the order in which they'd appear (@WaffleLapkin made a better example of this.), I'm not sure any such order is necessarily intuitive to the caller.
  2. Today when turbofishing you must specify all of the generics. And thus it's often nice for the APITs to not be part of what's turbofishable for mixing things. Take fn foo<T>(x: impl FnOnce(T) -> T), for example -- being able to call that as foo::<i32>(|x| x + 1) without being forced to put a _ in (like you would for fn foo<T, F: impl FnOnce(T) -> T>(x: F)) improves the experience for the caller. And thus using APITs for things where it's common to not care about the exact type (like closures and iterators) provides a nice bonus by not having the implicit generic in the turbofish list.
9 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.