Multiple parameters with same trait won't compile

I am just wondering on the syntax of rust:

If I define:

fn turn_direction<T>(p1: &T, p2: &T, p3: &T) -> isize
where  T: PointLike {..}

Why can I not call the function with three different structs, each implementing PointLike?

Instead I have to define:

fn turn_direction_flex<T, U, V>(p1: &T, p2: &U, p3: &V) -> isize
where
    T: PointLike,
    U: PointLike,
    V: PointLike,
{ .. }

Is it not enough to be PointLike?

Best,
Gunnar

Even without any trait bounds, a signature like

fn foo<T>(x: &T, y: &T, z: &T) -> … {}

would always mean “three parameters that are references to the same type T, which can be any type chosen by the caller of the function”.

Additional where bounds only further restrict the possibilities for the caller, so this interpretation of “when I write the same T multiple times, it always means the same type” never goes away.


Rust also has a convenience syntax for introducing unnamed type parameters with a trait bound directly inside of the signature, the impl Trait syntax. (Note that impl Trait in return types is very different.)

In function arguments, each occurrence of impl Trait will introduce a new unnamed type parameter, so you can make use of that and something like

fn turn_direction(p1: &impl PointLike, p2: &impl PointLike, p3: &impl PointLike) -> isize
{..}

is equivalent to

fn turn_direction_flex<T, U, V>(p1: &T, p2: &U, p3: &V) -> isize
where
    T: PointLike,
    U: PointLike,
    V: PointLike,
{ .. }

except that when you use this short-hand, you can no longer explicitly via “turbofish” specify these types in a

turn_direction_flex::<FirstType, SecondType, ThirdType>(first_arg, second_arg, thirg_arg)

style of call.

Unfortunately we do not have a way to easily reduce the repetition here, which can be a problem in case the trait bounds become very long. For your example code where it’s justPointLike”, that isn’t an issue of course, because that’s just a single trait without parameters any anything. While there are some workarounds for creating something trait aliases, the real thing as a “trait aliases” language feature doesn’t exist yet in stable Rust. (This feature is useful beyond the case of multiple arguments of a single function sharing a long and complicated trait bound. It can help just as well with the problem of many different functions needing to repeat the same long and complicated trait bound.)

3 Likes

Rust is statically typed and whether or not types are equal or not matters.

  • For assigning, e.g. swapping your parameters around or conditionally assigning them
  • For homogeneous types like Vec<T> or [T; 30] vs heterogeneous ones like tuples
  • For trait solving (e.g. what if PointLike: PartialEq[1])
  • For details like stack size and calling ABI
  • etc

  1. which allows comparing Ts to Ts, but not Ts to Us ↩︎

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.